diff --git a/DEPS b/DEPS index e1bacdaa..37cac0a 100644 --- a/DEPS +++ b/DEPS
@@ -204,7 +204,7 @@ # 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': '961f93287f84e7e7a7f5ff8a43c7adf14ca7fc42', + 'v8_revision': '9eaea2245f5c5133f2e05fcf0ad0062d009ca383', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -212,7 +212,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'fcb6b5a5c55ee35d232f35bcfa9c35aefc00f89e', + 'angle_revision': '10e6c1e43b65f24bac71ccd12c9a2a099e390ce8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -251,7 +251,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. - 'freetype_revision': '3facafa44e2ac49ac15359bf6c83110614a6cbf7', + 'freetype_revision': '56c610b145212b7acfb24a17e86fc0ba15aa3052', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -267,7 +267,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': 'ae003f552e4e16247758303d671076690c405c45', + 'catapult_revision': '759827265102502cc7f814572675b9685c351908', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -275,7 +275,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'a91304b7b16006cbf084e5cb7da6080b0c1cf62d', + 'devtools_frontend_revision': '14d4051e8a9f1fab057de9538e1db37bc742fd77', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -327,7 +327,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': '4814bdbdeae40186a61dfb7494390e64820daa4f', + 'dawn_revision': 'e96986149080ca37e82788c907f439bc070aaa7b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -366,7 +366,7 @@ 'ukey2_revision': '0275885d8e6038c39b8a8ca55e75d1d4d1727f47', # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'tint_revision': '12ed862c7ef2d64711cb7e5200f9c28992e2cd12', + 'tint_revision': '456aad3bced07d62e2b3bbf13f52bd1ac76c4094', # TODO(crbug.com/941824): The values below need to be kept in sync # between //DEPS and //buildtools/DEPS, so if you're updating one, @@ -899,7 +899,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' + '@' + 'fc23bc1c96acb0fa2fcc526204333fb9a373ecb6', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '34d74e1ebe96ea0136e999f661edf266519a9e68', 'condition': 'checkout_chromeos', }, @@ -1291,7 +1291,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '254ea334b65f8a7d5d4ab087f861df0572fa6af7', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '6cdb496e99b434eb28978a9a5519042cce88c3a9', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1551,7 +1551,7 @@ }, 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '0d863f72a8c747c1b41f2798e5201e1abcdaec2b', + Var('webrtc_git') + '/src.git' + '@' + 'cde4a9f66990ae8e78157dc24f876fc6418b1d3b', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1623,7 +1623,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2a242a6da146fbdfc29108e7f663f8af10c4fe08', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fc8456596a54c59d9f8d5eea8e99bcf982a2f4c3', 'condition': 'checkout_src_internal', }, @@ -1631,7 +1631,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'bGWD0dCUQSIgdz4mBoxEa-RzGSnD9QMw17rfdCA1yJMC', + 'version': 'zt2uwc_OGFM3k0PtlXL7onfFpGgcKV4FqGixO2OUNEoC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1642,7 +1642,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': '2vgKL8p-SUW0S-OFCowtelp1xuW-s-25Zm0z7AwTFPMC', + 'version': 'YTx5HPjHBFm4GXJxmOuhrfSBAL579U9AIc0Tpcnug2IC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/gfx/child_frame.cc b/android_webview/browser/gfx/child_frame.cc index d9d460b..ecab0ea 100644 --- a/android_webview/browser/gfx/child_frame.cc +++ b/android_webview/browser/gfx/child_frame.cc
@@ -43,7 +43,7 @@ if (frame_ptr) { layer_tree_frame_sink_id = frame_ptr->layer_tree_frame_sink_id; frame = std::move(frame_ptr->frame); - local_surface_id = frame_future->local_surface_id(); + local_surface_id = frame_ptr->local_surface_id; hit_test_region_list = std::move(frame_ptr->hit_test_region_list); } frame_future = nullptr;
diff --git a/android_webview/browser/gfx/child_frame.h b/android_webview/browser/gfx/child_frame.h index 880cef9..16116a2 100644 --- a/android_webview/browser/gfx/child_frame.h +++ b/android_webview/browser/gfx/child_frame.h
@@ -51,7 +51,7 @@ base::Optional<viz::HitTestRegionList> hit_test_region_list; // The id of the compositor this |frame| comes from. const viz::FrameSinkId frame_sink_id; - // local surface id of the frame, used with viz for webview + // Local surface id of the frame. Invalid if |frame| is null. viz::LocalSurfaceId local_surface_id; const gfx::Size viewport_size_for_tile_priority; const gfx::Transform transform_for_tile_priority;
diff --git a/android_webview/browser/gfx/hardware_renderer_viz.cc b/android_webview/browser/gfx/hardware_renderer_viz.cc index f6e08458..5e08a918 100644 --- a/android_webview/browser/gfx/hardware_renderer_viz.cc +++ b/android_webview/browser/gfx/hardware_renderer_viz.cc
@@ -159,8 +159,7 @@ if (child_frame->frame) { DCHECK(!viz_frame_submission_); - without_gpu_->SubmitChildCompositorFrame(child_id.local_surface_id(), - child_frame); + without_gpu_->SubmitChildCompositorFrame(child_frame); } gfx::Size frame_size = without_gpu_->GetChildFrameSize(); @@ -276,9 +275,7 @@ RenderThreadManager* state, RootFrameSinkGetter root_frame_sink_getter, AwVulkanContextProvider* context_provider) - : HardwareRenderer(state), - viz_frame_submission_(features::IsUsingVizFrameSubmissionForWebView()), - output_surface_provider_(context_provider) { + : HardwareRenderer(state), output_surface_provider_(context_provider) { DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_); DCHECK(output_surface_provider_.renderer_settings().use_skia_renderer); @@ -339,43 +336,10 @@ if (!child_frame_) return; - // Two problems currently can cause the content-generated LocalSurfaceId - // to remain the same even if a frame of a new size is submitted: - // * The content LocalSurfaceId is currently copied from browser, not - // the renderer when the renderer submits a frame - // * Synchronous compositor can resize the viewport in LTHI::OnDraw before - // a new LocalSurfaceId is committed. - // Therefore we do not use the LocalSurfaceId allocated by content, and - // instead generate our own LocalSurfaceId here for the root renderer frame. - if (!renderer_root_local_surface_id_allocator_ || - child_frame_->frame_sink_id != surface_id_.frame_sink_id() || - layer_tree_frame_sink_id_ != child_frame_->layer_tree_frame_sink_id) { - renderer_root_local_surface_id_allocator_ = - std::make_unique<viz::ParentLocalSurfaceIdAllocator>(); - layer_tree_frame_sink_id_ = child_frame_->layer_tree_frame_sink_id; - renderer_root_local_surface_id_ = viz::LocalSurfaceId(); - } - - if (!viz_frame_submission_ && child_frame_->frame) { - if (!renderer_root_local_surface_id_.is_valid() || - child_frame_->frame->size_in_pixels() != frame_size_ || - child_frame_->frame->device_scale_factor() != device_scale_factor_) { - renderer_root_local_surface_id_allocator_->GenerateId(); - renderer_root_local_surface_id_ = - renderer_root_local_surface_id_allocator_->GetCurrentLocalSurfaceId(); - frame_size_ = child_frame_->frame->size_in_pixels(); - device_scale_factor_ = child_frame_->frame->device_scale_factor(); - } - } - - viz::SurfaceId child_surface_id = - viz_frame_submission_ ? child_frame_->GetSurfaceId() - : viz::SurfaceId(child_frame_->frame_sink_id, - renderer_root_local_surface_id_); + viz::SurfaceId child_surface_id = child_frame_->GetSurfaceId(); if (child_surface_id.is_valid() && child_surface_id != surface_id_) { surface_id_ = child_surface_id; - if (viz_frame_submission_) - device_scale_factor_ = child_frame_->device_scale_factor; + device_scale_factor_ = child_frame_->device_scale_factor; } if (!surface_id_.is_valid())
diff --git a/android_webview/browser/gfx/hardware_renderer_viz.h b/android_webview/browser/gfx/hardware_renderer_viz.h index 7b97e6d..539912b 100644 --- a/android_webview/browser/gfx/hardware_renderer_viz.h +++ b/android_webview/browser/gfx/hardware_renderer_viz.h
@@ -35,19 +35,14 @@ void DestroyOnViz(); bool IsUsingVulkan() const; - const bool viz_frame_submission_; + // Information about last delegated frame. + float device_scale_factor_ = 0; + viz::SurfaceId surface_id_; // Used to create viz::OutputSurface and gl::GLSurface OutputSurfaceProviderWebview output_surface_provider_; - std::unique_ptr<viz::ParentLocalSurfaceIdAllocator> - renderer_root_local_surface_id_allocator_; - uint32_t layer_tree_frame_sink_id_ = 0u; - viz::LocalSurfaceId renderer_root_local_surface_id_; - float device_scale_factor_ = 1.0f; - gfx::Size frame_size_; - // These are accessed on the viz thread. std::unique_ptr<OnViz> on_viz_;
diff --git a/android_webview/browser/gfx/root_frame_sink.cc b/android_webview/browser/gfx/root_frame_sink.cc index 4eac7a7e..72eae52 100644 --- a/android_webview/browser/gfx/root_frame_sink.cc +++ b/android_webview/browser/gfx/root_frame_sink.cc
@@ -195,10 +195,9 @@ client_ = nullptr; } -void RootFrameSink::SubmitChildCompositorFrame( - const viz::LocalSurfaceId& local_surface_id, - ChildFrame* child_frame) { +void RootFrameSink::SubmitChildCompositorFrame(ChildFrame* child_frame) { DCHECK(child_frame->frame); + DCHECK(child_frame->local_surface_id.is_valid()); if (!child_sink_support_ || child_sink_support_->frame_sink_id() != child_frame->frame_sink_id || child_sink_support_->layer_tree_frame_sink_id() != @@ -211,7 +210,7 @@ } child_sink_support_->SubmitCompositorFrame( - local_surface_id, std::move(*child_frame->frame), + child_frame->local_surface_id, std::move(*child_frame->frame), std::move(child_frame->hit_test_region_list)); child_frame->frame.reset(); }
diff --git a/android_webview/browser/gfx/root_frame_sink.h b/android_webview/browser/gfx/root_frame_sink.h index afa412f..c607602 100644 --- a/android_webview/browser/gfx/root_frame_sink.h +++ b/android_webview/browser/gfx/root_frame_sink.h
@@ -58,8 +58,7 @@ bool IsChildSurface(const viz::FrameSinkId& frame_sink_id); void DettachClient(); - void SubmitChildCompositorFrame(const viz::LocalSurfaceId& local_surface_id, - ChildFrame* child_frame); + void SubmitChildCompositorFrame(ChildFrame* child_frame); viz::FrameTimingDetailsMap TakeChildFrameTimingDetailsMap(); gfx::Size GetChildFrameSize();
diff --git a/ash/public/cpp/external_arc/overlay/OWNERS b/ash/public/cpp/external_arc/overlay/OWNERS new file mode 100644 index 0000000..3511ed9 --- /dev/null +++ b/ash/public/cpp/external_arc/overlay/OWNERS
@@ -0,0 +1,3 @@ +file://components/arc/OWNERS + +lpique@chromium.org
diff --git a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc index ed0d9f9..25befe1e 100644 --- a/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc +++ b/ash/public/cpp/external_arc/overlay/arc_overlay_manager.cc
@@ -119,9 +119,6 @@ return; } - // Set a few properties of the shell root surface for its use as an overlay - shell_surface_base->root_surface()->SetFrame(exo::SurfaceFrameType::OVERLAY); - // Use the shell surface widget window as the overlay DCHECK(shell_surface_base->GetWidget()); DCHECK(shell_surface_base->GetWidget()->GetNativeWindow());
diff --git a/base/BUILD.gn b/base/BUILD.gn index 6b8ecb62..c2d829a 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -3874,7 +3874,6 @@ ] sources = [ - "test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java", "test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java", "test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java", "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java",
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc index b0403ef..6caebc0 100644 --- a/base/cpu_unittest.cc +++ b/base/cpu_unittest.cc
@@ -137,8 +137,6 @@ // sure that it's not optimized out by the compiler. __asm__ __volatile__("irg %0, %1" : "=r"(val) : "r"(ptr)); #endif // __ARM_FEATURE_MEMORY_TAGGING - } else { - GTEST_SKIP(); } #endif // ARCH_CPU_ARM64 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java deleted file mode 100644 index af570fb..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test; - -import android.app.Activity; -import android.content.Intent; -import android.support.test.runner.lifecycle.Stage; -import android.text.TextUtils; - -import androidx.annotation.NonNull; - -import org.junit.Assert; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.ContextUtils; -import org.chromium.base.Log; -import org.chromium.base.test.util.ApplicationTestUtils; - -/** - * A replacement for ActivityTestRule, designed for use in Chromium. This implementation supports - * launching the target activity through a launcher or redirect from another Activity. - * - * @param <T> The type of Activity this Rule will use. - */ -public class BaseActivityTestRule<T extends Activity> implements TestRule { - private static final String TAG = "BaseActivityTestRule"; - - private final Class<T> mActivityClass; - private boolean mFinishActivity = true; - private T mActivity; - - /** - * @param activityClass The Class of the Activity the TestRule will use. - */ - public BaseActivityTestRule(Class<T> activityClass) { - mActivityClass = activityClass; - } - - @Override - public Statement apply(final Statement base, final Description desc) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - base.evaluate(); - if (mFinishActivity && mActivity != null) { - ApplicationTestUtils.finishActivity(mActivity); - } - } - }; - } - - /** - * @param finishActivity Whether to finish the Activity between tests. This is only meaningful - * in the context of {@link Batch} tests. Non-batched tests will always finish Activities - * between tests. - */ - public void setFinishActivity(boolean finishActivity) { - mFinishActivity = finishActivity; - } - - /** - * @return The activity under test. - */ - public T getActivity() { - return mActivity; - } - - /** - * Set the Activity to be used by this TestRule. - */ - public void setActivity(T activity) { - mActivity = activity; - } - - /** - * Launches the Activity under test using the provided intent. - */ - public void launchActivity(@NonNull Intent startIntent) { - String packageName = ContextUtils.getApplicationContext().getPackageName(); - Assert.assertTrue(TextUtils.equals(startIntent.getPackage(), packageName) - || TextUtils.equals(startIntent.getComponent().getPackageName(), packageName)); - - startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - Log.d(TAG, String.format("Launching activity %s", mActivityClass.getName())); - - mActivity = ApplicationTestUtils.waitForActivityWithClass(mActivityClass, Stage.CREATED, - () -> ContextUtils.getApplicationContext().startActivity(startIntent)); - } -}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java index c044cb4..799c803 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java
@@ -5,9 +5,6 @@ package org.chromium.base.test.util; import android.app.Activity; -import android.content.Intent; -import android.os.Build; -import android.provider.Settings; import android.support.test.runner.lifecycle.ActivityLifecycleCallback; import android.support.test.runner.lifecycle.ActivityLifecycleMonitor; import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; @@ -29,16 +26,9 @@ /** Waits until the given activity transitions to the given state. */ public static void waitForActivityState(Activity activity, Stage stage) { - waitForActivityState(null, activity, stage); - } - - /** Waits until the given activity transitions to the given state. */ - public static void waitForActivityState(String failureReason, Activity activity, Stage stage) { - CriteriaHelper.pollUiThread( - () - -> { return sMonitor.getLifecycleStageOf(activity) == stage; }, - failureReason, ScalableTimeout.scaleTimeout(10000), - CriteriaHelper.DEFAULT_POLLING_INTERVAL); + CriteriaHelper.pollUiThread(() -> { + return sMonitor.getLifecycleStageOf(activity) == stage; + }, ScalableTimeout.scaleTimeout(10000), CriteriaHelper.DEFAULT_POLLING_INTERVAL); } /** Finishes the given activity and waits for its onDestroy() to be called. */ @@ -48,24 +38,7 @@ activity.finish(); } }); - try { - waitForActivityState( - "Failed to finish the Activity. Did you start a second Activity and not finish" - + " it?", - activity, Stage.DESTROYED); - } catch (Throwable e) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) throw e; - - // On L, there's a framework bug where Activities sometimes just don't get finished - // unless you start another Activity. - Intent intent = new Intent(Settings.ACTION_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - activity.startActivity(intent); - waitForActivityState( - "Failed to finish the Activity. Did you start a second Activity and not finish" - + " it?", - activity, Stage.DESTROYED); - } + waitForActivityState(activity, Stage.DESTROYED); } /** @@ -75,25 +48,11 @@ * @return The newly created Activity. */ public static <T extends Activity> T recreateActivity(T activity) { - return waitForActivityWithClass( - activity.getClass(), Stage.RESUMED, () -> activity.recreate()); - } - - /** - * Waits for an activity of the specified class to reach the specified Activity {@link Stage}, - * triggered by running the provided trigger. - * - * @param activityClass The class type to wait for. - * @param state The Activity {@link Stage} to wait for an activity of the right class type to - * reach. - * @param trigger The Runnable that will trigger the state change to wait for. - */ - public static <T extends Activity> T waitForActivityWithClass( - Class<? extends Activity> activityClass, Stage stage, Runnable trigger) { + final Class<?> activityClass = activity.getClass(); final CallbackHelper activityCallback = new CallbackHelper(); final AtomicReference<T> activityRef = new AtomicReference<>(); - ActivityLifecycleCallback stateListener = (Activity newActivity, Stage newStage) -> { - if (newStage == stage) { + ActivityLifecycleCallback stateListener = (Activity newActivity, Stage stage) -> { + if (stage == Stage.RESUMED) { if (!activityClass.isAssignableFrom(newActivity.getClass())) return; activityRef.set((T) newActivity); @@ -103,8 +62,8 @@ sMonitor.addLifecycleCallback(stateListener); try { - ThreadUtils.runOnUiThreadBlocking(() -> trigger.run()); - activityCallback.waitForCallback("No Activity reached target state.", 0); + ThreadUtils.runOnUiThreadBlocking(() -> activity.recreate()); + activityCallback.waitForCallback("Activity did not start as expected", 0); T createdActivity = activityRef.get(); Assert.assertNotNull("Activity reference is null.", createdActivity); return createdActivity;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 265801d..9912ea7 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20201126.3.1 +0.20201127.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index e61f1e3..9912ea7 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20201126.2.1 +0.20201127.1.1
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java index 25938528..2349270 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
@@ -46,9 +46,9 @@ BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder, Context context, @NonNull WebContents webContents, ActivityKeyboardVisibilityDelegate keyboardVisibilityDelegate, - ApplicationViewportInsetSupplier bottomInsetProvider, boolean skipOnboarding, - boolean isChromeCustomTab, @NonNull String initialUrl, Map<String, String> parameters, - String experimentIds, @Nullable String callerAccount, @Nullable String userName) { + ApplicationViewportInsetSupplier bottomInsetProvider, boolean isChromeCustomTab, + @NonNull String initialUrl, Map<String, String> parameters, String experimentIds, + @Nullable String callerAccount, @Nullable String userName) { if (shouldStartTriggerScript(parameters)) { if (TextUtils.isEmpty(parameters.get(PARAMETER_TRIGGER_SCRIPTS_BASE64)) && !UnifiedConsentServiceBridge.isUrlKeyedAnonymizedDataCollectionEnabled( @@ -80,9 +80,8 @@ parameters.put(PARAMETER_STARTED_WITH_TRIGGER_SCRIPT, "true"); startAutofillAssistantRegular(bottomSheetController, browserControls, compositorViewHolder, context, - webContents, skipOnboarding, isChromeCustomTab, - initialUrl, parameters, experimentIds, callerAccount, - userName); + webContents, isChromeCustomTab, initialUrl, parameters, + experimentIds, callerAccount, userName); } } }); @@ -99,9 +98,8 @@ isFirstTimeUser ? firstTimeUserScriptPath : returningUserScriptPath); startAutofillAssistantRegular(bottomSheetController, browserControls, - compositorViewHolder, context, webContents, skipOnboarding, - isChromeCustomTab, initialUrl, parameters, experimentIds, - callerAccount, userName); + compositorViewHolder, context, webContents, isChromeCustomTab, + initialUrl, parameters, experimentIds, callerAccount, userName); } }); return; @@ -109,8 +107,8 @@ // Regular flow for starting without dedicated trigger script. startAutofillAssistantRegular(bottomSheetController, browserControls, compositorViewHolder, - context, webContents, skipOnboarding, isChromeCustomTab, initialUrl, parameters, - experimentIds, callerAccount, userName); + context, webContents, isChromeCustomTab, initialUrl, parameters, experimentIds, + callerAccount, userName); } /** Whether {@code parameters} indicate that a trigger script should be started. */ @@ -140,10 +138,10 @@ */ private void startAutofillAssistantRegular(BottomSheetController bottomSheetController, BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder, - Context context, @NonNull WebContents webContents, boolean skipOnboarding, - boolean isChromeCustomTab, @NonNull String initialUrl, Map<String, String> parameters, - String experimentIds, @Nullable String callerAccount, @Nullable String userName) { - if (skipOnboarding) { + Context context, @NonNull WebContents webContents, boolean isChromeCustomTab, + @NonNull String initialUrl, Map<String, String> parameters, String experimentIds, + @Nullable String callerAccount, @Nullable String userName) { + if (!AutofillAssistantPreferencesUtil.getShowOnboarding()) { if (parameters.containsKey(PARAMETER_TRIGGER_SCRIPT_USED) || parameters.containsKey(PARAMETER_STARTED_WITH_TRIGGER_SCRIPT)) { AutofillAssistantMetrics.recordLiteScriptOnboarding(
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java index 38274c2..60810d6e 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataModel.java
@@ -365,9 +365,9 @@ @CalledByNative private static void addLoginChoice(List<AssistantLoginChoice> loginChoices, String identifier, String label, String sublabel, String sublabelAccessibilityHint, int priority, - @Nullable AssistantInfoPopup infoPopup) { - loginChoices.add(new AssistantLoginChoice( - identifier, label, sublabel, sublabelAccessibilityHint, priority, infoPopup)); + @Nullable AssistantInfoPopup infoPopup, @Nullable String editButtonContentDescription) { + loginChoices.add(new AssistantLoginChoice(identifier, label, sublabel, + sublabelAccessibilityHint, priority, infoPopup, editButtonContentDescription)); } /** Sets the list of available login choices. */
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginChoice.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginChoice.java index d5a7c57..6dc9951 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginChoice.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginChoice.java
@@ -18,6 +18,7 @@ private final int mPriority; private final String mSublabelAccessibilityHint; private final @Nullable AssistantInfoPopup mInfoPopup; + private final @Nullable String mEditButtonContentDescription; /** * @param identifier The unique identifier of this login choice. @@ -27,14 +28,16 @@ * @param priority The priority of this login choice (lower value == higher priority). Can be -1 * to indicate default/auto. * @param infoPopup Optional popup that provides further information for this login choice. + * @param editButtonContentDescription Optional content description for the edit button. */ public AssistantLoginChoice(String identifier, String label, String sublabel, - String sublabelAccessibilityHint, int priority, - @Nullable AssistantInfoPopup infoPopup) { + String sublabelAccessibilityHint, int priority, @Nullable AssistantInfoPopup infoPopup, + @Nullable String editButtonContentDescription) { super(identifier, label, sublabel, null); mPriority = priority; mSublabelAccessibilityHint = sublabelAccessibilityHint; mInfoPopup = infoPopup; + mEditButtonContentDescription = editButtonContentDescription; } public int getPriority() { @@ -48,4 +51,8 @@ public String getSublabelAccessibilityHint() { return mSublabelAccessibilityHint; } + + public @Nullable String getEditButtonContentDescription() { + return mEditButtonContentDescription; + } }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginSection.java index 18b3e33..4cf04166 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginSection.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantLoginSection.java
@@ -70,8 +70,11 @@ @Override protected String getEditButtonContentDescription(AssistantLoginChoice choice) { - // TODO(b/143862732): Send this a11y string from the backend. - return mContext.getString(R.string.learn_more); + if (choice.getEditButtonContentDescription() != null) { + return choice.getEditButtonContentDescription(); + } else { + return mContext.getString(R.string.learn_more); + } } @Override
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java index 2717c72..80b4009 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java
@@ -23,9 +23,10 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; +import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition; -import android.support.test.runner.lifecycle.Stage; +import android.app.Activity; import android.text.Spanned; import android.text.style.ClickableSpan; import android.view.View; @@ -42,10 +43,10 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.chromium.base.ActivityState; +import org.chromium.base.ApplicationStatus; import org.chromium.base.Callback; -import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.CriteriaHelper; import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator; @@ -56,6 +57,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -293,11 +295,8 @@ spannedMessage.getSpanEnd(spans[0])) .toString()); }); - CustomTabActivity activity = ApplicationTestUtils.waitForActivityWithClass( - CustomTabActivity.class, Stage.RESUMED, () -> spans[0].onClick(termsMessage)); - CriteriaHelper.pollUiThread( - () -> activity.getActivityTab().getUrlString().equals(expectedTermsUrl)); - activity.finish(); + spans[0].onClick(termsMessage); + waitUntil(() -> getOpenedUrlSpec().equals(expectedTermsUrl)); } @Test @@ -357,13 +356,12 @@ .toString() .replaceAll("\\s+", " ")); }); - CustomTabActivity activity = ApplicationTestUtils.waitForActivityWithClass( - CustomTabActivity.class, Stage.RESUMED, () -> spans[0].onClick(termsMessage)); - String url = mActivity.getResources() - .getText(R.string.autofill_assistant_google_terms_url) - .toString(); - CriteriaHelper.pollUiThread(() -> activity.getActivityTab().getUrlString().equals(url)); - activity.finish(); + spans[0].onClick(termsMessage); + waitUntil(() + -> getOpenedUrlSpec().equals( + mActivity.getResources() + .getText(R.string.autofill_assistant_google_terms_url) + .toString())); } /** Trigger onboarding and wait until it is fully displayed. */ @@ -372,4 +370,21 @@ TestThreadUtils.runOnUiThreadBlocking(() -> coordinator.show(callback)); waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed()); } + + // Get the newly opened Activity (through CustomTabActivity.showInfoPage) that happens on + // terms click. Return the URL of the current tab on that activity. + private String getOpenedUrlSpec() { + for (Activity runningActivity : ApplicationStatus.getRunningActivities()) { + if (runningActivity instanceof CustomTabActivity + && ApplicationStatus.getStateForActivity(runningActivity) + == ActivityState.RESUMED) { + return ChromeTabUtils + .getUrlOnUiThread(((CustomTabActivity) runningActivity) + .getTabModelSelector() + .getCurrentTab()) + .getSpec(); + } + } + return ""; + } }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java index e830ba8..07bb330 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantCollectUserDataUiTest.java
@@ -667,7 +667,7 @@ model.set(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE, true); model.set(AssistantCollectUserDataModel.AVAILABLE_LOGINS, Collections.singletonList(new AssistantLoginChoice( - "id", "Guest", "Description of guest checkout", "", 0, null))); + "id", "Guest", "Description of guest checkout", "", 0, null, ""))); }); /* Non-empty sections should not display the 'add' button in their title. */ @@ -1525,16 +1525,90 @@ model.set(AssistantCollectUserDataModel.LOGIN_SECTION_TITLE, "Login options"); model.set(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE, true); model.set(AssistantCollectUserDataModel.AVAILABLE_LOGINS, + Collections.singletonList(new AssistantLoginChoice("id", "Guest checkout", "", + "", 0, infoPopup, "Description of edit button"))); + }); + + onView(withText("Login options")).perform(click()); + onView(withContentDescription("Description of edit button")).perform(click()); + onView(withText("Guest checkout")).check(matches(isDisplayed())); + onView(withText("Text explanation.")).check(matches(isDisplayed())); + onView(withText(mTestRule.getActivity().getString(R.string.close))).perform(click()); + onView(withContentDescription("Description of edit button")).check(matches(isDisplayed())); + } + + @Test + @MediumTest + public void testSuppliedNonEmptyEditContentDescriptionIsUsed() throws Exception { + String contentDescription = "Description of edit button"; + AssistantCollectUserDataModel model = new AssistantCollectUserDataModel(); + AssistantCollectUserDataCoordinator coordinator = createCollectUserDataCoordinator(model); + AutofillAssistantCollectUserDataTestHelper.MockDelegate delegate = + new AutofillAssistantCollectUserDataTestHelper.MockDelegate(); + + AssistantInfoPopup infoPopup = new AssistantInfoPopup("", "", null, null, null); + TestThreadUtils.runOnUiThreadBlocking(() -> { + model.set(AssistantCollectUserDataModel.DELEGATE, delegate); + model.set(AssistantCollectUserDataModel.VISIBLE, true); + model.set(AssistantCollectUserDataModel.LOGIN_SECTION_TITLE, "Login options"); + model.set(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE, true); + model.set(AssistantCollectUserDataModel.AVAILABLE_LOGINS, Collections.singletonList(new AssistantLoginChoice( - "id", "Guest checkout", "", "", 0, infoPopup))); + "id", "Guest checkout", "", "", 0, infoPopup, contentDescription))); + }); + + onView(withText("Login options")).perform(click()); + onView(withContentDescription(contentDescription)).check(matches(isDisplayed())); + } + + @Test + @MediumTest + public void testSuppliedEmptyEditContentDescriptionIsUsed() throws Exception { + String contentDescription = ""; + AssistantCollectUserDataModel model = new AssistantCollectUserDataModel(); + AssistantCollectUserDataCoordinator coordinator = createCollectUserDataCoordinator(model); + AutofillAssistantCollectUserDataTestHelper.MockDelegate delegate = + new AutofillAssistantCollectUserDataTestHelper.MockDelegate(); + + AssistantInfoPopup infoPopup = new AssistantInfoPopup("", "", null, null, null); + TestThreadUtils.runOnUiThreadBlocking(() -> { + model.set(AssistantCollectUserDataModel.DELEGATE, delegate); + model.set(AssistantCollectUserDataModel.VISIBLE, true); + model.set(AssistantCollectUserDataModel.LOGIN_SECTION_TITLE, "Login options"); + model.set(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE, true); + model.set(AssistantCollectUserDataModel.AVAILABLE_LOGINS, + Collections.singletonList(new AssistantLoginChoice( + "id", "Guest checkout", "", "", 0, infoPopup, contentDescription))); + }); + + onView(withText("Login options")).perform(click()); + onView(withContentDescription(contentDescription)).check(matches(isDisplayed())); + } + + @Test + @MediumTest + public void testWhenNullEditContentDescriptionIsSuppliedIconDescriptionIsUsed() + throws Exception { + String contentDescription = null; + AssistantCollectUserDataModel model = new AssistantCollectUserDataModel(); + AssistantCollectUserDataCoordinator coordinator = createCollectUserDataCoordinator(model); + AutofillAssistantCollectUserDataTestHelper.MockDelegate delegate = + new AutofillAssistantCollectUserDataTestHelper.MockDelegate(); + + AssistantInfoPopup infoPopup = new AssistantInfoPopup("", "", null, null, null); + TestThreadUtils.runOnUiThreadBlocking(() -> { + model.set(AssistantCollectUserDataModel.DELEGATE, delegate); + model.set(AssistantCollectUserDataModel.VISIBLE, true); + model.set(AssistantCollectUserDataModel.LOGIN_SECTION_TITLE, "Login options"); + model.set(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE, true); + model.set(AssistantCollectUserDataModel.AVAILABLE_LOGINS, + Collections.singletonList(new AssistantLoginChoice( + "id", "Guest checkout", "", "", 0, infoPopup, contentDescription))); }); onView(withText("Login options")).perform(click()); onView(withContentDescription(mTestRule.getActivity().getString(R.string.learn_more))) - .perform(click()); - onView(withText("Guest checkout")).check(matches(isDisplayed())); - onView(withText("Text explanation.")).check(matches(isDisplayed())); - onView(withText(mTestRule.getActivity().getString(R.string.close))).perform(click()); + .check(matches(isDisplayed())); } private View getPaymentSummaryErrorView(ViewHolder viewHolder) {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java index 51cef43..03a1924 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantInputActionIntegrationTest.java
@@ -31,24 +31,36 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto; +import org.chromium.chrome.browser.autofill_assistant.proto.CheckElementIsOnTopProto; import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto; import org.chromium.chrome.browser.autofill_assistant.proto.ChipType; import org.chromium.chrome.browser.autofill_assistant.proto.ClickProto; import org.chromium.chrome.browser.autofill_assistant.proto.ClickType; +import org.chromium.chrome.browser.autofill_assistant.proto.ClientIdProto; +import org.chromium.chrome.browser.autofill_assistant.proto.ElementConditionProto; import org.chromium.chrome.browser.autofill_assistant.proto.KeyboardValueFillStrategy; import org.chromium.chrome.browser.autofill_assistant.proto.OptionalStep; import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionProto; import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionStatusProto; import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto; import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto.Choice; +import org.chromium.chrome.browser.autofill_assistant.proto.ReleaseElementsProto; +import org.chromium.chrome.browser.autofill_assistant.proto.ScrollIntoViewProto; import org.chromium.chrome.browser.autofill_assistant.proto.SelectOptionProto; import org.chromium.chrome.browser.autofill_assistant.proto.SelectorProto; import org.chromium.chrome.browser.autofill_assistant.proto.SelectorProto.Filter; +import org.chromium.chrome.browser.autofill_assistant.proto.SendClickEventProto; +import org.chromium.chrome.browser.autofill_assistant.proto.SendKeystrokeEventsProto; +import org.chromium.chrome.browser.autofill_assistant.proto.SetFieldValueProto; import org.chromium.chrome.browser.autofill_assistant.proto.SetFormFieldValueProto; import org.chromium.chrome.browser.autofill_assistant.proto.SetFormFieldValueProto.KeyPress; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto; import org.chromium.chrome.browser.autofill_assistant.proto.SupportedScriptProto.PresentationProto; import org.chromium.chrome.browser.autofill_assistant.proto.TextFilter; +import org.chromium.chrome.browser.autofill_assistant.proto.TextValue; +import org.chromium.chrome.browser.autofill_assistant.proto.WaitForDocumentToBecomeInteractiveProto; +import org.chromium.chrome.browser.autofill_assistant.proto.WaitForDomProto; +import org.chromium.chrome.browser.autofill_assistant.proto.WaitForElementToBecomeStableProto; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.flags.ChromeSwitches; @@ -472,6 +484,76 @@ assertThat(processed.get(2).getStatus(), is(ProcessedActionStatusProto.ELEMENT_NOT_ON_TOP)); } + @Test + @MediumTest + public void setTextWithMiniActions() throws Exception { + ArrayList<ActionProto> list = new ArrayList<>(); + + SelectorProto element = SelectorProto.newBuilder() + .addFilters(Filter.newBuilder().setCssSelector("#input1")) + .build(); + ClientIdProto clientId = ClientIdProto.newBuilder().setIdentifier("e").build(); + list.add((ActionProto) ActionProto.newBuilder() + .setWaitForDom( + WaitForDomProto.newBuilder().setTimeoutMs(1000).setWaitCondition( + ElementConditionProto.newBuilder() + .setMatch(element) + .setClientId(clientId))) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setWaitForDocumentToBecomeInteractive( + WaitForDocumentToBecomeInteractiveProto.newBuilder() + .setClientId(clientId) + .setTimeoutInMs(1000)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setWaitForElementToBecomeStable( + WaitForElementToBecomeStableProto.newBuilder() + .setClientId(clientId) + .setStableCheckMaxRounds(10) + .setStableCheckIntervalMs(200)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setScrollIntoView(ScrollIntoViewProto.newBuilder().setClientId(clientId)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setCheckElementIsOnTop( + CheckElementIsOnTopProto.newBuilder().setClientId(clientId)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setSetFieldValue( + SetFieldValueProto.newBuilder().setClientId(clientId).setValue( + TextValue.newBuilder().setText(""))) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setSendClickEvent(SendClickEventProto.newBuilder().setClientId(clientId)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setSendKeystrokeEvents( + SendKeystrokeEventsProto.newBuilder() + .setClientId(clientId) + .setDelayInMs(0) + .setValue(TextValue.newBuilder().setText("Value"))) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setReleaseElements( + ReleaseElementsProto.newBuilder().addClientIds(clientId)) + .build()); + list.add((ActionProto) ActionProto.newBuilder() + .setPrompt(PromptProto.newBuilder().setMessage("Done").addChoices( + Choice.newBuilder())) + .build()); + + AutofillAssistantTestScript script = new AutofillAssistantTestScript(TEST_SCRIPT, list); + + assertThat(getElementValue(mTestRule.getWebContents(), "input1"), is("helloworld1")); + + runScript(script); + + waitUntilViewMatchesCondition(withText("Done"), isCompletelyDisplayed()); + assertThat(getElementValue(mTestRule.getWebContents(), "input1"), is("Value")); + } + private void runScript(AutofillAssistantTestScript script) { AutofillAssistantTestService testService = new AutofillAssistantTestService(Collections.singletonList(script));
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java index 6cfaeb4..a300227 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTriggerScriptIntegrationTest.java
@@ -431,4 +431,54 @@ waitUntilViewMatchesCondition(withText("Trigger script"), isCompletelyDisplayed()); } + + @Test + @MediumTest + @Features.EnableFeatures(ChromeFeatureList.AUTOFILL_ASSISTANT_PROACTIVE_HELP) + public void dontShownOnboardingIfAcceptedInDifferentTab() { + TriggerScriptProto.Builder triggerScript = + TriggerScriptProto + .newBuilder() + /* no trigger condition */ + .setUserInterface(createDefaultUI("Trigger script", + /* bubbleMessage = */ "", + /* withProgressBar = */ true) + .setRegularScriptLoadingStatusMessage( + "Loading regular script")); + + GetTriggerScriptsResponseProto triggerScripts = + (GetTriggerScriptsResponseProto) GetTriggerScriptsResponseProto.newBuilder() + .addTriggerScripts(triggerScript) + .build(); + setupTriggerScripts(triggerScripts); + AutofillAssistantPreferencesUtil.setInitialPreferences(true); + SharedPreferencesManager.getInstance().writeBoolean( + ChromePreferenceKeys.AUTOFILL_ASSISTANT_ONBOARDING_ACCEPTED, false); + startAutofillAssistantOnTab(TEST_PAGE); + + waitUntilViewMatchesCondition(withText("Trigger script"), isCompletelyDisplayed()); + + // Simulate the user accepting the onboarding in a different tab. + SharedPreferencesManager.getInstance().writeBoolean( + ChromePreferenceKeys.AUTOFILL_ASSISTANT_ONBOARDING_ACCEPTED, true); + + ArrayList<ActionProto> list = new ArrayList<>(); + list.add((ActionProto) ActionProto.newBuilder() + .setPrompt(PromptProto.newBuilder().addChoices( + PromptProto.Choice.newBuilder().setChip( + ChipProto.newBuilder().setText("Done")))) + .build()); + AutofillAssistantTestScript script = new AutofillAssistantTestScript( + (SupportedScriptProto) SupportedScriptProto.newBuilder() + .setPath(TEST_PAGE) + .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip( + ChipProto.newBuilder().setText("Done"))) + .build(), + list); + setupRegularScripts(script); + + onView(withText("Continue")).perform(click()); + waitUntilViewMatchesCondition(withText("Done"), isCompletelyDisplayed()); + onView(withText("Loading regular script")).check(matches(isDisplayed())); + } }
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java index 9d7762e..a6fe542 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/TestingAutofillAssistantModuleEntryProvider.java
@@ -69,9 +69,8 @@ CompositorViewHolder compositorViewHolder, Context context, @NonNull WebContents webContents, ActivityKeyboardVisibilityDelegate keyboardVisibilityDelegate, - ApplicationViewportInsetSupplier bottomInsetProvider, boolean skipOnboarding, - boolean isChromeCustomTab, @NonNull String initialUrl, - Map<String, String> parameters, String experimentIds, + ApplicationViewportInsetSupplier bottomInsetProvider, boolean isChromeCustomTab, + @NonNull String initialUrl, Map<String, String> parameters, String experimentIds, @Nullable String callerAccount, @Nullable String userName) {} @Override
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index 4a75cf5..c1d6dd3 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -164,7 +164,6 @@ activity.getCompositorViewHolder(), activity, tab.getWebContents(), activity.getWindowAndroid().getKeyboardDelegate(), activity.getWindowAndroid().getApplicationBottomInsetProvider(), - !AutofillAssistantPreferencesUtil.getShowOnboarding(), activity instanceof CustomTabActivity, arguments.getInitialUrl(), arguments.getParameters(), arguments.getExperimentIds(), arguments.getCallerAccount(), arguments.getUserName());
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java index dc194378..062db851 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java
@@ -37,9 +37,9 @@ BrowserControlsStateProvider browserControls, CompositorViewHolder compositorViewHolder, Context context, @NonNull WebContents webContents, ActivityKeyboardVisibilityDelegate keyboardVisibilityDelegate, - ApplicationViewportInsetSupplier bottomInsetProvider, boolean skipOnboarding, - boolean isChromeCustomTab, @NonNull String initialUrl, Map<String, String> parameters, - String experimentIds, @Nullable String callerAccount, @Nullable String userName); + ApplicationViewportInsetSupplier bottomInsetProvider, boolean isChromeCustomTab, + @NonNull String initialUrl, Map<String, String> parameters, String experimentIds, + @Nullable String callerAccount, @Nullable String userName); /** * Returns a {@link AutofillAssistantActionHandler} instance tied to the activity owning the * given bottom sheet, and scrim view.
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java index a3ae2c4..51b95d2 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -65,7 +65,6 @@ import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; -import org.chromium.base.test.util.ScalableTimeout; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.compositor.layouts.Layout; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone; @@ -173,7 +172,7 @@ Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); mActivityTestRule.prepareUrlIntent(intent, null); - mActivityTestRule.launchActivity(intent); + mActivityTestRule.startActivityCompletely(intent); } public static Bitmap createThumbnailBitmapAndWriteToFile(int tabId) { @@ -272,8 +271,7 @@ TestThreadUtils.runOnUiThreadBlocking( () -> mActivityTestRule.getActivity().startDelayedNativeInitializationForTests()); CriteriaHelper.pollUiThread( - mActivityTestRule.getActivity().getTabModelSelector()::isTabStateInitialized, - ScalableTimeout.scaleTimeout(10000L), CriteriaHelper.DEFAULT_POLLING_INTERVAL); + mActivityTestRule.getActivity().getTabModelSelector()::isTabStateInitialized); Assert.assertTrue(LibraryLoader.getInstance().isInitialized()); } @@ -570,7 +568,6 @@ RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(i); if (viewHolder != null) { ImageView thumbnail = viewHolder.itemView.findViewById(R.id.tab_thumbnail); - if (!(thumbnail.getDrawable() instanceof BitmapDrawable)) return false; BitmapDrawable drawable = (BitmapDrawable) thumbnail.getDrawable(); Bitmap bitmap = drawable.getBitmap(); if (bitmap == null) return false;
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java index 260b84d6..19a30c7 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -91,7 +91,7 @@ Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); mActivityTestRule.prepareUrlIntent(intent, null); - mActivityTestRule.launchActivity(intent); + mActivityTestRule.startActivityCompletely(intent); } @Before
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index c7b94a6..9d29913 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -811,7 +811,7 @@ @CommandLineFlags.Add({BASE_PARAMS + "/single/exclude_mv_tiles/true" + "/show_last_active_tab_only/true/show_stack_tab_switcher/true"}) public void - testShow_SingleAsHomepageV2_FromResumeShowStart() throws Exception { + testShow_SingleAsHomepageV2_FromResumeShowStart() throws ExecutionException { // clang-format on if (!mImmediateReturn) return; @@ -831,7 +831,7 @@ pressHome(); // Simulates pressing Chrome's icon and launching Chrome from warm start. - mActivityTestRule.resumeMainActivityFromLauncher(); + startMainActivityFromLauncher(); CriteriaHelper.pollUiThread( () -> cta.getLayoutManager() != null && cta.getLayoutManager().overviewVisible());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestService.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestService.java index 8d81d3b..79cb0ae 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestService.java
@@ -214,11 +214,6 @@ } } - @Override - public boolean isShowingUi() { - return mPaymentUiService.isShowingUI(); - } - // Implements BrowserPaymentRequest: @Override public String showAppSelector(boolean isShowWaitingForUpdatedDetails, PaymentItem total,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java index f3d994cd0..66cee2d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUiService.java
@@ -447,11 +447,6 @@ return mMinimalUi; } - /** @return Whether the Payment Request or Minimal UIs are showing. */ - public boolean isShowingUI() { - return mPaymentRequestUI != null || mMinimalUi != null; - } - // Implements PaymentUiServiceTestInterface: @Override @VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java index 5fb5ba9..1b8a581 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java
@@ -12,6 +12,7 @@ import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.components.external_intents.AuthenticatorNavigationInterceptor; import org.chromium.components.external_intents.ExternalNavigationHandler; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult; import org.chromium.components.external_intents.InterceptNavigationDelegateClient; import org.chromium.components.external_intents.InterceptNavigationDelegateImpl; import org.chromium.components.external_intents.RedirectHandler; @@ -116,6 +117,10 @@ @Override public void onNavigationStarted(NavigationParams params) {} + @Override + public void onDecisionReachedForNavigation( + NavigationParams params, OverrideUrlLoadingResult overrideUrlLoadingResult) {} + public void initializeWithDelegate(InterceptNavigationDelegateImpl delegate) { mInterceptNavigationDelegate = delegate; mTab.addObserver(mTabObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index 55cc509..2d53db6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -130,10 +130,10 @@ @Override public boolean hasTab() { - // TODO(https://crbug.com/1147131): Remove the isInitialized() and isDestroyed checks when - // we no longer wait for TAB_CLOSED events to remove this tab. Otherwise there is a chance - // we use this tab after {@link Tab#destroy()} is called. - return mTab != null && mTab.isInitialized() && !mTab.isDestroyed(); + // TODO(dtrainor, tedchoc): Remove the isInitialized() check when we no longer wait for + // TAB_CLOSED events to remove this tab. Otherwise there is a chance we use this tab after + // {@link ChromeTab#destroy()} is called. + return mTab != null && mTab.isInitialized(); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java index d2e0260..279eb8d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
@@ -15,6 +15,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; @@ -71,6 +72,7 @@ @After public void tearDown() throws Exception { AppIndexingUtil.setCallbackForTesting(null); + ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); } private static class CopylessHelper extends CallbackHelper {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java index 723653c..cee2800 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
@@ -8,11 +8,13 @@ import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; @@ -34,6 +36,11 @@ @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + @After + public void tearDown() throws Exception { + ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); + } + /** * Verify launch the activity with URL. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java index 8640a48..2d586b71 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
@@ -11,11 +11,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.CoreMatchers.allOf; import static org.junit.Assert.assertEquals; -import static org.chromium.chrome.test.util.ViewUtils.onViewWaiting; - import android.support.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -84,7 +81,7 @@ @MediumTest public void testPromoNotShownAfterBeingDismissed() { mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity()); - onViewWaiting(allOf(withId(R.id.signin_promo_view_container), isDisplayed())); + onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed())); onView(withId(R.id.signin_promo_close_button)).perform(click()); onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java index 733c40d..645fad0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -204,9 +204,8 @@ } @After - public void tearDown() throws Exception { + public void tearDown() { if (mTestServer != null) mTestServer.stopAndDestroyServer(); - if (mBookmarkActivity != null) ApplicationTestUtils.finishActivity(mBookmarkActivity); } @AfterClass @@ -284,7 +283,7 @@ // Click the star button again to launch the edit activity. MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity(), R.id.bookmark_this_page_id); - waitForEditActivity().finish(); + waitForEditActivity(); } @Test @@ -315,9 +314,8 @@ currentSnackbar.getController().onAction(null); }); - BookmarkEditActivity activity = waitForEditActivity(); + waitForEditActivity(); SnackbarManager.setDurationForTesting(0); - activity.finish(); } @Test @@ -1733,13 +1731,12 @@ RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); } - private BookmarkEditActivity waitForEditActivity() { + private void waitForEditActivity() { CriteriaHelper.pollUiThread(() -> { Criteria.checkThat(ApplicationStatus.getLastTrackedFocusedActivity(), IsInstanceOf.instanceOf(BookmarkEditActivity.class)); }); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - return (BookmarkEditActivity) ApplicationStatus.getLastTrackedFocusedActivity(); } private ChromeTabbedActivity waitForTabbedActivity() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java index c6d9b533..6fc157e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
@@ -17,7 +17,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -45,18 +44,14 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class ClearBrowsingDataFragmentBasicTest { + @Rule public final ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + @Rule public final SettingsActivityTestRule<ClearBrowsingDataFragmentBasic> mSettingsActivityTestRule = new SettingsActivityTestRule<>(ClearBrowsingDataFragmentBasic.class); - // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish - // CTA won't work. - @Rule - public final RuleChain mRuleChain = - RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule); - @Rule public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index c47a13b..8bc1feb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -2466,10 +2466,10 @@ sActivityTestRule.getActivity().getActivityTab())); final NavigationParams navigationParams = new NavigationParams( "intent://test/#Intent;scheme=test;package=com.chrome.test;end", "", - false /* isPost */, true /* hasUserGesture */, PageTransition.LINK, - false /* isRedirect */, true /* isExternalProtocol */, true /* isMainFrame */, - true /* isRendererInitiated */, false /* hasUserGestureCarryover */, - null /* initiatorOrigin */); + 0 /* navigationId */, false /* isPost */, true /* hasUserGesture */, + PageTransition.LINK, false /* isRedirect */, true /* isExternalProtocol */, + true /* isMainFrame */, true /* isRendererInitiated */, + false /* hasUserGestureCarryover */, null /* initiatorOrigin */); InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { @@ -2496,16 +2496,16 @@ sActivityTestRule.getActivity().getActivityTab())); final NavigationParams initialNavigationParams = new NavigationParams("http://test.com", "", - false /* isPost */, true /* hasUserGesture */, PageTransition.LINK, - false /* isRedirect */, false /* isExternalProtocol */, true /* isMainFrame */, - true /* isRendererInitiated */, false /* hasUserGestureCarryover */, - null /* initiatorOrigin */); + 0 /* navigationId */, false /* isPost */, true /* hasUserGesture */, + PageTransition.LINK, false /* isRedirect */, false /* isExternalProtocol */, + true /* isMainFrame */, true /* isRendererInitiated */, + false /* hasUserGestureCarryover */, null /* initiatorOrigin */); final NavigationParams redirectedNavigationParams = new NavigationParams( "intent://test/#Intent;scheme=test;package=com.chrome.test;end", "", - false /* isPost */, false /* hasUserGesture */, PageTransition.LINK, - true /* isRedirect */, true /* isExternalProtocol */, true /* isMainFrame */, - true /* isRendererInitiated */, false /* hasUserGestureCarryover */, - null /* initiatorOrigin */); + 0 /* navigationId */, false /* isPost */, false /* hasUserGesture */, + PageTransition.LINK, true /* isRedirect */, true /* isExternalProtocol */, + true /* isMainFrame */, true /* isRendererInitiated */, + false /* hasUserGestureCarryover */, null /* initiatorOrigin */); InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override @@ -2535,10 +2535,10 @@ sActivityTestRule.getActivity().getActivityTab())); final NavigationParams navigationParams = new NavigationParams( "intent://test/#Intent;scheme=test;package=com.chrome.test;end", "", - false /* isPost */, false /* hasUserGesture */, PageTransition.LINK, - false /* isRedirect */, true /* isExternalProtocol */, true /* isMainFrame */, - true /* isRendererInitiated */, false /* hasUserGestureCarryover */, - null /* initiatorOrigin */); + 0 /* navigationId */, false /* isPost */, false /* hasUserGesture */, + PageTransition.LINK, false /* isRedirect */, true /* isExternalProtocol */, + true /* isMainFrame */, true /* isRendererInitiated */, + false /* hasUserGestureCarryover */, null /* initiatorOrigin */); InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 96b2323a..8101eec 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -707,7 +707,7 @@ IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW); filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme()); final ActivityMonitor monitor = - InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, true); + InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false); openAppMenuAndAssertMenuShown(); PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { MenuItem item =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java index e832ecf..ff48c21 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java
@@ -4,20 +4,29 @@ package org.chromium.chrome.browser.customtabs; +import android.app.Activity; import android.content.Intent; +import android.support.test.InstrumentationRegistry; -import androidx.annotation.NonNull; - +import org.hamcrest.Matchers; import org.junit.Assert; +import org.chromium.base.ApplicationStatus; import org.chromium.base.FeatureList; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.Criteria; +import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.ScalableTimeout; +import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabTestUtils; import org.chromium.chrome.test.ChromeActivityTestRule; import java.util.Collections; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Custom ActivityTestRule for all instrumentation tests that require a {@link CustomTabActivity}. @@ -45,13 +54,29 @@ } @Override - public void launchActivity(@NonNull Intent intent) { + public void startActivityCompletely(Intent intent) { if (!FeatureList.hasTestFeatures()) { FeatureList.setTestFeatures( Collections.singletonMap(ChromeFeatureList.SHARE_BY_DEFAULT_IN_CCT, true)); } putCustomTabIdInIntent(intent); - super.launchActivity(intent); + int currentIntentId = getCustomTabIdFromIntent(intent); + + Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent); + Assert.assertNotNull("Main activity did not start", activity); + CriteriaHelper.pollUiThread(() -> { + for (Activity runningActivity : ApplicationStatus.getRunningActivities()) { + if (runningActivity instanceof CustomTabActivity) { + CustomTabActivity customTabActivity = (CustomTabActivity) runningActivity; + final int customTabIdInActivity = + getCustomTabIdFromIntent(customTabActivity.getIntent()); + if (currentIntentId != customTabIdInActivity) continue; + setActivity(customTabActivity); + return true; + } + } + return false; + }); } /** @@ -59,8 +84,33 @@ * initialized. */ public void startCustomTabActivityWithIntent(Intent intent) { + DeferredStartupHandler.setExpectingActivityStartupForTesting(); startActivityCompletely(intent); + waitForActivityNativeInitializationComplete(); + CriteriaHelper.pollUiThread(() -> { + Criteria.checkThat(getActivity().getActivityTab(), Matchers.notNullValue()); + }); final Tab tab = getActivity().getActivityTab(); + final CallbackHelper pageLoadFinishedHelper = new CallbackHelper(); + tab.addObserver(new EmptyTabObserver() { + @Override + public void onLoadStopped(Tab tab, boolean toDifferentDocument) { + pageLoadFinishedHelper.notifyCalled(); + } + }); + try { + if (tab.isLoading()) { + pageLoadFinishedHelper.waitForCallback( + 0, 1, LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } catch (TimeoutException e) { + Assert.fail(); + } + Assert.assertTrue("Deferred startup never completed", + DeferredStartupHandler.waitForDeferredStartupCompleteForTesting( + STARTUP_TIMEOUT_MS)); + Assert.assertNotNull(tab); + Assert.assertNotNull(tab.getView()); Assert.assertTrue(TabTestUtils.isCustomTab(tab)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java index 3821874..a07414a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
@@ -111,7 +111,8 @@ @Test @Feature("CustomTabFromChrome") @LargeTest - public void testIntentWithRedirectToApp() { + public void + testIntentWithRedirectToApp() { final String redirectUrl = "https://maps.google.com/maps?q=1600+amphitheatre+parkway"; final String initialUrl = mServerRule.getServer().getURL("/chrome/test/data/android/redirect/js_redirect.html" @@ -122,7 +123,7 @@ + Base64.encodeToString( ApiCompatibilityUtils.getBytesUtf8(redirectUrl), Base64.URL_SAFE)); - mActivityRule.launchActivity(getCustomTabFromChromeIntent(initialUrl, true)); + mActivityRule.startActivityCompletely(getCustomTabFromChromeIntent(initialUrl, true)); mActivityRule.waitForActivityNativeInitializationComplete(); final AtomicReference<InterceptNavigationDelegateImpl> navigationDelegate =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java index af9727f..0899713 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
@@ -9,10 +9,12 @@ import androidx.test.filters.LargeTest; +import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.MinAndroidSdkLevel; @@ -35,6 +37,11 @@ public DisplayCutoutTestRule mTestRule = new DisplayCutoutTestRule<ChromeActivity>(ChromeActivity.class); + @After + public void tearDown() throws Exception { + ApplicationTestUtils.finishActivity(mTestRule.getActivity()); + } + /** * Test that no safe area is applied when we have viewport fit auto */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java index cc76495e..3dc82eb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -13,7 +13,6 @@ import android.net.Uri; import android.os.SystemClock; import android.support.test.InstrumentationRegistry; -import android.support.test.runner.lifecycle.Stage; import android.text.TextUtils; import android.util.Base64; @@ -29,14 +28,10 @@ import org.junit.runner.RunWith; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.ContextUtils; -import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.ScalableTimeout; -import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.tab.EmptyTabObserver; @@ -429,36 +424,24 @@ @Test @SmallTest - public void testRedirectionFromIntentCold() throws Exception { - Context context = ContextUtils.getApplicationContext(); + public void testRedirectionFromIntent() { + // Test cold-start. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mTestServer.getURL(NAVIGATION_FROM_JAVA_REDIRECTION_PAGE))); - intent.setClassName(context, ChromeLauncherActivity.class.getName()); + Context targetContext = InstrumentationRegistry.getTargetContext(); + intent.setClassName(targetContext, ChromeLauncherActivity.class.getName()); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - ChromeTabbedActivity activity = ApplicationTestUtils.waitForActivityWithClass( - ChromeTabbedActivity.class, Stage.CREATED, () -> context.startActivity(intent)); - mActivityTestRule.setActivity(activity); - - CriteriaHelper.pollUiThread(() -> { - Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(1)); - }, ScalableTimeout.scaleTimeout(10000L), CriteriaHelper.DEFAULT_POLLING_INTERVAL); - ApplicationTestUtils.waitForActivityState(activity, Stage.STOPPED); - } - - @Test - @SmallTest - public void testRedirectionFromIntentWarm() throws Exception { - Context context = ContextUtils.getApplicationContext(); - mActivityTestRule.startMainActivityOnBlankPage(); - Intent intent = new Intent(Intent.ACTION_VIEW, - Uri.parse(mTestServer.getURL(NAVIGATION_FROM_JAVA_REDIRECTION_PAGE))); - intent.setClassName(context, ChromeLauncherActivity.class.getName()); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + InstrumentationRegistry.getInstrumentation().startActivitySync(intent); CriteriaHelper.pollUiThread( () -> Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(1))); + + // Test warm start. + mActivityTestRule.startMainActivityOnBlankPage(); + targetContext.startActivity(intent); + + CriteriaHelper.pollUiThread( + () -> Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(2))); } @Test @@ -506,6 +489,7 @@ String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI); loadUrlAndWaitForIntentUrl(originalUrl, true, false, false, null, false, "null_scheme"); } + @Test @LargeTest public void testIntentURIWithEmptySchemeDoesNothing() throws TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java index 3579486..7934a16 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
@@ -16,7 +16,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.chromium.base.ActivityState; @@ -65,16 +64,12 @@ private EmbeddedTestServer mTestServer; + @Rule public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + @Rule public SettingsActivityTestRule<HomepageSettings> mSettingsActivityTestRule = new SettingsActivityTestRule<>(HomepageSettings.class); - // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish - // CTA won't work. - @Rule - public final RuleChain mRuleChain = - RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule); - @Rule public HomepageTestRule mHomepageTestRule = new HomepageTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java index a273db8..703521dd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java
@@ -14,7 +14,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UserActionTester; @@ -105,8 +104,9 @@ Assert.assertNotNull("Custom URI radio button is null.", mCustomUriRadioButton); } - private void finishSettingsActivity() throws Exception { - ApplicationTestUtils.finishActivity(mTestRule.getActivity()); + private void finishSettingsActivity() { + mTestRule.getActivity().finish(); + mTestRule.waitTillActivityIsDestroyed(); } @Test @@ -394,7 +394,7 @@ @Test @SmallTest @Feature({"Homepage"}) - public void testCheckRadioButtons() throws Exception { + public void testCheckRadioButtons() { mHomepageTestRule.useCustomizedHomepageForTest(TEST_URL_FOO); launchSettingsActivity(); LocationChangedCounter counter = new LocationChangedCounter(); @@ -446,7 +446,7 @@ @Test @SmallTest @Feature({"Homepage"}) - public void testChangeCustomized() throws Exception { + public void testChangeCustomized() { mHomepageTestRule.useChromeNTPForTest(); launchSettingsActivity(); LocationChangedCounter actionCounter = new LocationChangedCounter();
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 98254843..5c0af74 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
@@ -218,7 +218,7 @@ // mSlowPage will hang for 2 seconds before sending a response. It should be enough to // put Chrome in background before the page is committed. mTabbedActivityTestRule.prepareUrlIntent(intent, mSlowPage); - mTabbedActivityTestRule.launchActivity(intent); + mTabbedActivityTestRule.startActivityCompletely(intent); // Put Chrome in background before the page is committed. ChromeApplicationTestUtils.fireHomeScreenIntent(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java index 8c2cbab..cdbf6b55 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
@@ -250,7 +250,6 @@ // Offline indicator should not be shown. checkOfflineIndicatorVisibility(downloadActivity, false); - downloadActivity.finish(); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java index 012b466..4485b232 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java
@@ -13,8 +13,6 @@ import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.ASSISTANT_VOICE_SEARCH_ENABLED; -import android.support.test.runner.lifecycle.Stage; - import androidx.test.filters.MediumTest; import org.junit.After; @@ -28,7 +26,6 @@ import org.mockito.junit.MockitoRule; import org.chromium.base.Callback; -import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; @@ -36,7 +33,6 @@ import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.chrome.browser.settings.SettingsActivity; import org.chromium.chrome.browser.settings.SettingsLauncherImpl; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; @@ -134,19 +130,16 @@ public void testDialogInteractivity_LearnMoreButton() { showConsentUi(); - SettingsActivity activity = ApplicationTestUtils.waitForActivityWithClass( - SettingsActivity.class, Stage.RESUMED, () -> { - ClickUtils.clickButton( - mAssistantVoiceSearchConsentUi.getContentView().findViewById( - R.id.avs_consent_ui_learn_more)); - mBottomSheetTestSupport.endAllAnimations(); - }); + TestThreadUtils.runOnUiThreadBlocking(() -> { + ClickUtils.clickButton(mAssistantVoiceSearchConsentUi.getContentView().findViewById( + R.id.avs_consent_ui_learn_more)); + mBottomSheetTestSupport.endAllAnimations(); + }); onView(withText(mActivityTestRule.getActivity().getResources().getString( R.string.avs_setting_category_title))) .check(matches(isDisplayed())); Mockito.verify(mCallback, Mockito.times(0)).onResult(/* meaningless value */ true); - activity.finish(); } @Test @@ -163,4 +156,4 @@ }); Mockito.verify(mCallback, Mockito.timeout(1000)).onResult(false); } -} +} \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java index 419276e..61515dd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -108,7 +108,7 @@ private void loadUrlAndOpenPageInfo(String url) { mActivityTestRule.loadUrl(url); - onViewWaiting(allOf(withId(R.id.location_bar_status_icon), isDisplayed())).perform(click()); + onView(withId(R.id.location_bar_status_icon)).perform(click()); } private View getPageInfoView() { @@ -187,6 +187,8 @@ // Choose a fixed, "random" port to create stable screenshots. mTestServerRule.setServerPort(424242); mTestServerRule.setServerUsesHttps(true); + + mActivityTestRule.startMainActivityOnBlankPage(); } @After @@ -210,7 +212,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowOnInsecureHttpWebsite() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); mTestServerRule.setServerUsesHttps(false); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_HttpWebsite"); @@ -224,7 +225,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowOnSecureWebsite() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_SecureWebsite"); } @@ -238,7 +238,6 @@ @DisabledTest(message = "https://crbug.com/1133770") @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowOnExpiredCertificateWebsite() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); mTestServerRule.setCertificateType(ServerCertificate.CERT_EXPIRED); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_ExpiredCertWebsite"); @@ -252,7 +251,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testChromePage() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); loadUrlAndOpenPageInfo("chrome://version/"); mRenderTestRule.render(getPageInfoView(), "PageInfo_InternalSite"); } @@ -266,7 +264,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowWithPermissions() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); mIsSystemLocationSettingEnabled = false; addSomePermissions(mTestServerRule.getServer().getURL("/")); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); @@ -281,7 +278,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowWithCookieBlocking() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_CookieBlocking"); @@ -295,7 +291,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowWithPermissionsAndCookieBlocking() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); addSomePermissions(mTestServerRule.getServer().getURL("/")); setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); @@ -310,7 +305,6 @@ @Feature({"RenderTest"}) @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowWithDefaultSettingPermissions() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); addDefaultSettingPermissions(mTestServerRule.getServer().getURL("/")); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_DefaultSettingPermissions"); @@ -324,7 +318,6 @@ @Feature({"RenderTest"}) @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowOnSecureWebsiteV2() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); mRenderTestRule.render(getPageInfoView(), "PageInfo_SecureWebsiteV2"); } @@ -353,7 +346,6 @@ @Feature({"RenderTest"}) @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowConnectionInfoSubpage() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); onView(withId(R.id.page_info_connection_row)).perform(click()); mRenderTestRule.render(getPageInfoView(), "PageInfo_ConnectionInfoSubpage"); @@ -367,7 +359,6 @@ @Feature({"RenderTest"}) @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowPermissionsSubpage() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); addSomePermissions(mTestServerRule.getServer().getURL("/")); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); onView(withId(R.id.page_info_permissions_row)).perform(click()); @@ -382,7 +373,6 @@ @Feature({"RenderTest"}) @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testShowCookiesSubpage() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); onView(withId(R.id.page_info_cookies_row)).perform(click()); @@ -397,7 +387,6 @@ @MediumTest @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testNoPermissionsSubpage() throws IOException { - mActivityTestRule.startMainActivityOnBlankPage(); loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml)); View dialog = (View) getPageInfoView().getParent(); onView(withId(R.id.page_info_permissions_row)) @@ -412,7 +401,6 @@ @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) @FlakyTest(message = "https://crbug.com/1147236") public void testClearCookiesOnSubpage() throws Exception { - mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.loadUrl(mTestServerRule.getServer().getURL(sSiteDataHtml)); // Create cookies. expectHasCookies(false); @@ -438,7 +426,6 @@ @MediumTest @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testResetPermissionsOnSubpage() throws Exception { - mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.loadUrl(mTestServerRule.getServer().getURL(sSiteDataHtml)); String url = mTestServerRule.getServer().getURL("/"); // Create permissions. @@ -466,7 +453,6 @@ @MediumTest @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2) public void testPaintPreview() { - mActivityTestRule.startMainActivityOnBlankPage(); TestThreadUtils.runOnUiThreadBlocking(() -> { final ChromeActivity activity = mActivityTestRule.getActivity(); final Tab tab = activity.getActivityTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java index 2c90ae8..3b5375ab2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -1245,7 +1245,6 @@ @Override public void create(PaymentAppFactoryDelegate delegate) { Runnable createApp = () -> { - if (delegate.getParams().hasClosed()) return; boolean canMakePayment = delegate.getParams().getMethodData().containsKey(mAppMethodName); delegate.onCanMakePaymentCalculated(canMakePayment);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java index 947221f..aa1888d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -15,7 +15,6 @@ import static org.mockito.Mockito.verify; import android.app.Activity; -import android.support.test.InstrumentationRegistry; import android.text.TextUtils; import android.view.View; @@ -102,7 +101,7 @@ private final SyncTestRule mSyncTestRule = new SyncTestRule(); private final SettingsActivityTestRule<MainSettings> mSettingsActivityTestRule = - new SettingsActivityTestRule<>(MainSettings.class); + new SettingsActivityTestRule<>(MainSettings.class, true); // SettingsActivity needs to be initialized and destroyed with the mock // signin environment setup in SyncTestRule @@ -134,7 +133,6 @@ @Before public void setup() { MockitoAnnotations.initMocks(this); - InstrumentationRegistry.getInstrumentation().setInTouchMode(true); PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck); SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncherImpl); DeveloperSettings.setIsEnabledForTests(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java index 6783423..516bc1db0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
@@ -22,6 +22,7 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.test.filters.MediumTest; +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -33,6 +34,7 @@ import org.chromium.base.Callback; import org.chromium.base.test.params.ParameterAnnotations; import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.Batch; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CriteriaHelper; @@ -118,6 +120,11 @@ mActivityTestRule.startMainActivityOnBlankPage(); } + @After + public void tearDown() throws Exception { + ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); + } + @AfterClass public static void tearDownAfterActivityDestroyed() { ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java index 5383798..16095c4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java
@@ -100,7 +100,7 @@ @Test @SmallTest public void testLaunchActivity() { - startManageSpaceActivity().finish(); + startManageSpaceActivity(); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java index d0a1c47..b42cd0d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -18,7 +18,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; @@ -41,18 +40,14 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class AccountManagementFragmentTest { + @Rule public final SettingsActivityTestRule<AccountManagementFragment> mSettingsActivityTestRule = new SettingsActivityTestRule<>(AccountManagementFragment.class); + @Rule public final ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); - // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish - // CTA won't work. - @Rule - public final RuleChain mRuleChain = - RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule); - @Rule public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java index 9b38421..dc9d76a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
@@ -16,7 +16,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; @@ -52,17 +51,13 @@ @Rule public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule(); + @Rule public final ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); - public final SettingsActivityTestRule<GoogleServicesSettings> mSettingsActivityTestRule = - new SettingsActivityTestRule<>(GoogleServicesSettings.class); - - // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish - // CTA won't work. @Rule - public final RuleChain mRuleChain = - RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule); + public final SettingsActivityTestRule<GoogleServicesSettings> mSettingsActivityTestRule = + new SettingsActivityTestRule<>(GoogleServicesSettings.class, true); @Before public void setUp() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java index 2acd095..9c90fe6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -90,7 +90,7 @@ private final SyncTestRule mSyncTestRule = new SyncTestRule(); private final SettingsActivityTestRule<ManageSyncSettings> mSettingsActivityTestRule = - new SettingsActivityTestRule<>(ManageSyncSettings.class); + new SettingsActivityTestRule<>(ManageSyncSettings.class, true); // SettingsActivity needs to be initialized and destroyed with the mock // signin environment setup in SyncTestRule
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java index 559a75f..76da0b0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
@@ -62,7 +62,7 @@ @Rule public final SettingsActivityTestRule<ManageSyncSettings> mSettingsActivityTestRule = - new SettingsActivityTestRule<>(ManageSyncSettings.class); + new SettingsActivityTestRule<>(ManageSyncSettings.class, true); @Rule public final ChromeRenderTestRule mRenderTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java index 458cdfa..cfd5d948 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -4,12 +4,6 @@ package org.chromium.chrome.browser.sync; -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - import android.app.Activity; import android.app.PendingIntent; import android.content.Context; @@ -19,7 +13,6 @@ import androidx.annotation.Nullable; import androidx.preference.TwoStatePreference; -import androidx.test.espresso.contrib.RecyclerViewActions; import org.junit.Assert; import org.junit.runner.Description; @@ -38,7 +31,6 @@ import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule; import org.chromium.chrome.test.util.browser.signin.SigninTestUtil; import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; -import org.chromium.components.browser_ui.widget.R; import org.chromium.components.signin.base.CoreAccountInfo; import org.chromium.components.sync.ModelType; import org.chromium.components.sync.protocol.AutofillWalletSpecifics; @@ -418,9 +410,12 @@ // UI interaction convenience methods. public void togglePreference(final TwoStatePreference pref) { - onView(withId(R.id.recycler_view)) - .perform(RecyclerViewActions.actionOnItem( - hasDescendant(withText(pref.getTitle().toString())), click())); + TestThreadUtils.runOnUiThreadBlocking(() -> { + boolean newValue = !pref.isChecked(); + pref.getOnPreferenceChangeListener().onPreferenceChange(pref, newValue); + pref.setChecked(newValue); + }); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java index c715a63..2611d9a5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java
@@ -64,11 +64,9 @@ LevelDBPersistedTabDataStorage.setSkipNativeAssertionsForTesting(true); } - @UiThreadTest @SmallTest @Test public void testFactoryMethod() { - Profile realProfile = Profile.getLastUsedRegularProfile(); LevelDBPersistedTabDataStorageFactory factory = new LevelDBPersistedTabDataStorageFactory(); Profile.setLastUsedProfileForTesting(mProfile1); LevelDBPersistedTabDataStorage profile1Storage = factory.create(); @@ -78,8 +76,6 @@ LevelDBPersistedTabDataStorage profile1StorageAgain = factory.create(); Assert.assertEquals(profile1Storage, profile1StorageAgain); Assert.assertNotEquals(profile1Storage, profile2Storage); - // Restore the original profile so the Activity can shut down correctly. - Profile.setLastUsedProfileForTesting(realProfile); } @UiThreadTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java index cf1a94e0..12907e88 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
@@ -597,7 +597,7 @@ intent.addCategory(Intent.CATEGORY_LAUNCHER); mActivityTestRule.prepareUrlIntent(intent, url); Assert.assertFalse(mInflated.get()); - mActivityTestRule.launchActivity(intent); + mActivityTestRule.startActivityCompletely(intent); if (mUseInstantStart) { CriteriaHelper.pollUiThread(mInflated::get); } else {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java index fc5fc02..33af832 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -263,7 +263,7 @@ IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW); filter.addDataScheme("https"); final ActivityMonitor monitor = - InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, true); + InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false); RevampedContextMenuUtils.selectContextMenuItem(InstrumentationRegistry.getInstrumentation(), null /* activity to check for focus after click */,
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index f6e4c82..02a736c 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-89.0.4336.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-89.0.4337.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index fccea13..0a4b3ed 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1411,6 +1411,8 @@ "previews/previews_ui_tab_helper.h", "previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc", "previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h", + "privacy_sandbox/privacy_sandbox_prefs.cc", + "privacy_sandbox/privacy_sandbox_prefs.h", "process_resource_usage.cc", "process_resource_usage.h", "process_singleton.h",
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc index ed3119a..334bf20c 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -112,12 +112,18 @@ jsublabel_accessibility_hint = ConvertUTF8ToJavaString( env, login_choice.sublabel_accessibility_hint.value()); } + base::android::ScopedJavaLocalRef<jstring> + jedit_button_content_description = nullptr; + if (login_choice.edit_button_content_description.has_value()) { + jedit_button_content_description = base::android::ConvertUTF8ToJavaString( + env, login_choice.edit_button_content_description.value()); + } Java_AssistantCollectUserDataModel_addLoginChoice( env, jlist, ConvertUTF8ToJavaString(env, login_choice.identifier), ConvertUTF8ToJavaString(env, login_choice.label), ConvertUTF8ToJavaString(env, login_choice.sublabel), jsublabel_accessibility_hint, login_choice.preselect_priority, - jinfo_popup); + jinfo_popup, jedit_button_content_description); } return jlist; }
diff --git a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc index 68aa455..36956c1 100644 --- a/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc +++ b/chrome/browser/chromeos/arc/file_system_watcher/arc_file_system_watcher_service.cc
@@ -257,7 +257,7 @@ watcher_ = std::make_unique<base::FilePathWatcher>(); // On Linux, base::FilePathWatcher::Watch() always returns true. - watcher_->Watch(cros_dir_, true, + watcher_->Watch(cros_dir_, base::FilePathWatcher::Type::kRecursive, base::BindRepeating(&FileSystemWatcher::OnFilePathChanged, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager_unittest.cc b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager_unittest.cc index f0535ec6..c8696d1 100644 --- a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager_unittest.cc +++ b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager_unittest.cc
@@ -100,7 +100,8 @@ // so this test should NOT depend on the assumption. base::FilePathWatcher watcher; base::RunLoop run_loop1; - watcher.Watch(base::FilePath(socket_path), false, + watcher.Watch(base::FilePath(socket_path), + base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(base::BindLambdaForTesting( [&run_loop1](const base::FilePath& path, bool error) { EXPECT_FALSE(error);
diff --git a/chrome/browser/chromeos/file_manager/file_watcher.cc b/chrome/browser/chromeos/file_manager/file_watcher.cc index 4adea11..47b10b2 100644 --- a/chrome/browser/chromeos/file_manager/file_watcher.cc +++ b/chrome/browser/chromeos/file_manager/file_watcher.cc
@@ -30,7 +30,8 @@ DCHECK(!callback.is_null()); std::unique_ptr<base::FilePathWatcher> watcher(new base::FilePathWatcher); - if (!watcher->Watch(watch_path, false /* recursive */, callback)) + if (!watcher->Watch(watch_path, base::FilePathWatcher::Type::kNonRecursive, + callback)) return nullptr; return watcher.release();
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc index 4c4e7788..42854758 100644 --- a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc
@@ -377,12 +377,19 @@ "en-US"); OobeScreenWaiter(WelcomeView::kScreenId).Wait(); const std::string locale = "ru"; + test::LanguageReloadObserver observer(welcome_screen()); welcome_screen()->SetApplicationLocale(locale); - test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); - WaitForScreenExit(); + observer.Wait(); + EXPECT_EQ(g_browser_process->local_state()->GetString( language::prefs::kApplicationLocale), locale); + EXPECT_EQ(g_browser_process->GetApplicationLocale(), locale); + + // We need to proceed otherwise welcome screen would reset language on the + // next show. + test::OobeJS().TapOnPath({"connect", "welcomeScreen", "welcomeNextButton"}); + WaitForScreenExit(); } IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, SelectedLanguage) { @@ -390,6 +397,7 @@ EXPECT_EQ(g_browser_process->local_state()->GetString( language::prefs::kApplicationLocale), locale); + EXPECT_EQ(g_browser_process->GetApplicationLocale(), locale); } IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, A11yVirtualKeyboard) {
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 9df1100..9510dc5d 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1709,9 +1709,11 @@ if (!GetOobeUI()) return; - // Check for tests configuration. - if (wizard_context_->skip_to_update_for_tests) + // Check for tests configurations. + if (wizard_context_->skip_to_update_for_tests || + wizard_context_->skip_to_login_for_tests) { return; + } if (screen_needed) ShowHIDDetectionScreen();
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc index ccccf06..0b976e07 100644 --- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc +++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
@@ -15,11 +15,11 @@ #include "chromeos/constants/chromeos_switches.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "services/network/public/cpp/shared_url_loader_factory.h" using content::BrowserThread; @@ -170,8 +170,9 @@ std::vector<std::string> scopes; scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth); scopes.push_back(GaiaConstants::kOAuthWrapBridgeUserInfoScope); - access_token_fetcher_.reset(new OAuth2AccessTokenFetcherImpl( - this, system_url_loader_factory_, oauth2_refresh_token_)); + access_token_fetcher_ = + GaiaAccessTokenFetcher::CreateExchangeRefreshTokenForAccessTokenInstance( + this, system_url_loader_factory_, oauth2_refresh_token_); access_token_fetcher_->Start( GaiaUrls::GetInstance()->oauth2_chrome_client_id(), GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
diff --git a/chrome/browser/chromeos/policy/upload_job_unittest.cc b/chrome/browser/chromeos/policy/upload_job_unittest.cc index 07177b8..0632222c 100644 --- a/chrome/browser/chromeos/policy/upload_job_unittest.cc +++ b/chrome/browser/chromeos/policy/upload_job_unittest.cc
@@ -23,8 +23,8 @@ #include "content/public/test/browser_task_environment.h" #include "google_apis/gaia/core_account_id.h" #include "google_apis/gaia/fake_oauth2_access_token_manager.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/google_service_auth_error.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "google_apis/gaia/oauth2_access_token_manager.h" #include "net/http/http_status_code.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -172,8 +172,9 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, OAuth2AccessTokenConsumer* consumer) override { EXPECT_EQ(CoreAccountId(kRobotAccountId), account_id); - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory, "fake_refresh_token"); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory, "fake_refresh_token"); } bool HasRefreshToken(const CoreAccountId& account_id) const override {
diff --git a/chrome/browser/chromeos/printing/automatic_usb_printer_configurer.cc b/chrome/browser/chromeos/printing/automatic_usb_printer_configurer.cc index 3dc2025..86933cf 100644 --- a/chrome/browser/chromeos/printing/automatic_usb_printer_configurer.cc +++ b/chrome/browser/chromeos/printing/automatic_usb_printer_configurer.cc
@@ -89,6 +89,10 @@ void AutomaticUsbPrinterConfigurer::OnSetupComplete(const Printer& printer, PrinterSetupResult result) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_); + if (result == PrinterSetupResult::kPrinterIsNotAutoconfigurable) { + installation_manager_->PrinterIsNotAutoconfigurable(printer); + return; + } if (result != PrinterSetupResult::kSuccess) { LOG(ERROR) << "Unable to autoconfigure usb printer " << printer.id(); return;
diff --git a/chrome/browser/chromeos/printing/automatic_usb_printer_configurer_unittest.cc b/chrome/browser/chromeos/printing/automatic_usb_printer_configurer_unittest.cc index 5eb7b8c0..8c24442 100644 --- a/chrome/browser/chromeos/printing/automatic_usb_printer_configurer_unittest.cc +++ b/chrome/browser/chromeos/printing/automatic_usb_printer_configurer_unittest.cc
@@ -104,8 +104,17 @@ return installed_printers_.contains(printer.id()); } + void PrinterIsNotAutoconfigurable(const Printer& printer) override { + printers_marked_as_not_autoconf_.insert(printer.id()); + } + + bool IsMarkedAsNotAutoconfigurable(const Printer& printer) { + return printers_marked_as_not_autoconf_.contains(printer.id()); + } + private: base::flat_set<std::string> installed_printers_; + base::flat_set<std::string> printers_marked_as_not_autoconf_; }; class FakeUsbPrinterNotificationController @@ -326,4 +335,22 @@ fake_notification_controller_->IsNotificationDisplayed(printer_id)); } +TEST_F(AutomaticUsbPrinterConfigurerTest, RegisterAutoconfFailureForIppUsb) { + const std::string printer1_id = "id1"; + const std::string printer2_id = "id2"; + const Printer printer1 = CreateIppUsbPrinter(printer1_id); + const Printer printer2 = CreateIppUsbPrinter(printer2_id); + + fake_printer_configurer_->AssignPrinterSetupResult( + printer1_id, PrinterSetupResult::kPrinterIsNotAutoconfigurable); + + fake_observable_printers_manager_.AddNearbyAutomaticPrinter(printer1); + fake_observable_printers_manager_.AddNearbyAutomaticPrinter(printer2); + + EXPECT_TRUE( + fake_installation_manager_->IsMarkedAsNotAutoconfigurable(printer1)); + EXPECT_FALSE( + fake_installation_manager_->IsMarkedAsNotAutoconfigurable(printer2)); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc index bfa6e46..f18c19f 100644 --- a/chrome/browser/chromeos/printing/cups_printers_manager.cc +++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -222,6 +222,13 @@ } // Public API function. + void PrinterIsNotAutoconfigurable(const Printer& printer) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_); + ppd_resolution_tracker_.MarkPrinterAsNotAutoconfigurable(printer.id()); + RebuildDetectedLists(); + } + + // Public API function. base::Optional<Printer> GetPrinter(const std::string& id) const override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_); if (!user_printers_allowed_.GetValue()) { @@ -559,37 +566,7 @@ printers_.Insert(PrinterClass::kAutomatic, detected.printer); continue; } - if (ppd_resolution_tracker_.IsResolutionComplete(detected_printer_id)) { - auto printer = detected.printer; - if (!ppd_resolution_tracker_.WasResolutionSuccessful( - detected_printer_id)) { - if (!printer.supports_ippusb()) { - // We couldn't figure out this printer, so it's in the discovered - // class. - if (printer.IsUsbProtocol()) { - printer.set_manufacturer( - ppd_resolution_tracker_.GetManufacturer(detected_printer_id)); - } - printers_.Insert(PrinterClass::kDiscovered, printer); - continue; - } - // If the detected printer supports ipp-over-usb and we could not find - // a ppd for it, then we switch to the ippusb scheme and mark it as - // autoconf. - printer.SetUri( - Uri(base::StringPrintf("ippusb://%04x_%04x/ipp/print", - detected.ppd_search_data.usb_vendor_id, - detected.ppd_search_data.usb_product_id))); - printer.mutable_ppd_reference()->autoconf = true; - printers_.Insert(PrinterClass::kAutomatic, printer); - } else { - // We have a ppd reference, so we think we can set this up - // automatically. - *printer.mutable_ppd_reference() = - ppd_resolution_tracker_.GetPpdReference(detected_printer_id); - printers_.Insert(PrinterClass::kAutomatic, printer); - } - } else { + if (!ppd_resolution_tracker_.IsResolutionComplete(detected_printer_id)) { // Didn't find an entry for this printer in the PpdReferences cache. We // need to ask PpdProvider whether or not it can determine a // PpdReference. If there's not already an outstanding request for one, @@ -603,7 +580,47 @@ weak_ptr_factory_.GetWeakPtr(), detected_printer_id)); } + continue; } + auto printer = detected.printer; + if (ppd_resolution_tracker_.WasResolutionSuccessful( + detected_printer_id)) { + // We have a ppd reference, so we think we can set this up + // automatically. + *printer.mutable_ppd_reference() = + ppd_resolution_tracker_.GetPpdReference(detected_printer_id); + printers_.Insert(PrinterClass::kAutomatic, printer); + continue; + } + if (!printer.supports_ippusb()) { + // Detected printer does not supports ipp-over-usb, so we cannot set it + // up automatically. We have to move it to the discovered class. + if (printer.IsUsbProtocol()) { + printer.set_manufacturer( + ppd_resolution_tracker_.GetManufacturer(detected_printer_id)); + } + printers_.Insert(PrinterClass::kDiscovered, printer); + continue; + } + // Detected printer supports ipp-over-usb and we could not find a ppd for + // it. We can try to set it up automatically (by IPP Everywhere). + if (ppd_resolution_tracker_.IsMarkedAsNotAutoconfigurable( + detected_printer_id)) { + // We have tried to autoconfigure the printer in the past and the + // process failed because of the lack of IPP Everywhere support. + // The printer must be treated as discovered printer. + printer.mutable_ppd_reference()->autoconf = false; + printers_.Insert(PrinterClass::kDiscovered, printer); + continue; + } + // We will try to autoconfigure the printer. We have to switch to + // the ippusb scheme. + printer.SetUri( + Uri(base::StringPrintf("ippusb://%04x_%04x/ipp/print", + detected.ppd_search_data.usb_vendor_id, + detected.ppd_search_data.usb_product_id))); + printer.mutable_ppd_reference()->autoconf = true; + printers_.Insert(PrinterClass::kAutomatic, printer); } }
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h index 1afb078..56a5ad77 100644 --- a/chrome/browser/chromeos/printing/cups_printers_manager.h +++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -103,15 +103,10 @@ virtual void AddObserver(Observer* observer) = 0; virtual void RemoveObserver(Observer* observer) = 0; - // Record that the given printers has been installed in CUPS for usage. - // Parameter |is_automatic| should be set to true if the printer was - // saved automatically (without requesting additional information - // from the user). + // Implementation of PrinterInstallationManager interface. void PrinterInstalled(const Printer& printer, bool is_automatic) override = 0; - - // Returns true if |printer| is currently installed in CUPS with this - // configuration. bool IsPrinterInstalled(const Printer& printer) const override = 0; + void PrinterIsNotAutoconfigurable(const Printer& printer) override = 0; // Look for a printer with the given id in any class. Returns a copy of the // printer if found, base::nullopt if not found.
diff --git a/chrome/browser/chromeos/printing/ppd_resolution_state.cc b/chrome/browser/chromeos/printing/ppd_resolution_state.cc index a766dd8..5e32ff6 100644 --- a/chrome/browser/chromeos/printing/ppd_resolution_state.cc +++ b/chrome/browser/chromeos/printing/ppd_resolution_state.cc
@@ -9,7 +9,9 @@ namespace chromeos { PpdResolutionState::PpdResolutionState() - : is_inflight_(true), is_ppd_resolution_successful_(false) {} + : is_inflight_(true), + is_ppd_resolution_successful_(false), + is_not_autoconfigurable_(false) {} PpdResolutionState::PpdResolutionState(PpdResolutionState&& other) = default; PpdResolutionState& PpdResolutionState::operator=(PpdResolutionState&& rhs) = default; @@ -58,4 +60,12 @@ return is_ppd_resolution_successful_; } +void PpdResolutionState::MarkPrinterAsNotAutoconfigurable() { + is_not_autoconfigurable_ = true; +} + +bool PpdResolutionState::IsMarkedAsNotAutoconfigurable() const { + return is_not_autoconfigurable_; +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/ppd_resolution_state.h b/chrome/browser/chromeos/printing/ppd_resolution_state.h index 1c13d20..d376097 100644 --- a/chrome/browser/chromeos/printing/ppd_resolution_state.h +++ b/chrome/browser/chromeos/printing/ppd_resolution_state.h
@@ -40,9 +40,17 @@ // Returns true if a PpdReference was retrieved. bool WasResolutionSuccessful() const; + // Marks the printer as not autoconfigurable. This flag is set after + // unsuccessful attempt to configure the printer automatically. + void MarkPrinterAsNotAutoconfigurable(); + + // Returns true <=> the method above was called for the printer. + bool IsMarkedAsNotAutoconfigurable() const; + private: bool is_inflight_; bool is_ppd_resolution_successful_; + bool is_not_autoconfigurable_; Printer::PpdReference ppd_reference_; std::string usb_manufacturer_;
diff --git a/chrome/browser/chromeos/printing/ppd_resolution_tracker.cc b/chrome/browser/chromeos/printing/ppd_resolution_tracker.cc index c7016a5..d55455d 100644 --- a/chrome/browser/chromeos/printing/ppd_resolution_tracker.cc +++ b/chrome/browser/chromeos/printing/ppd_resolution_tracker.cc
@@ -90,4 +90,14 @@ return base::Contains(printer_state_, printer_id); } +void PpdResolutionTracker::MarkPrinterAsNotAutoconfigurable( + const std::string& printer_id) { + printer_state_.at(printer_id).MarkPrinterAsNotAutoconfigurable(); +} + +bool PpdResolutionTracker::IsMarkedAsNotAutoconfigurable( + const std::string& printer_id) const { + return printer_state_.at(printer_id).IsMarkedAsNotAutoconfigurable(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/ppd_resolution_tracker.h b/chrome/browser/chromeos/printing/ppd_resolution_tracker.h index ccdd00980..9af996ce 100644 --- a/chrome/browser/chromeos/printing/ppd_resolution_tracker.h +++ b/chrome/browser/chromeos/printing/ppd_resolution_tracker.h
@@ -55,6 +55,14 @@ const Printer::PpdReference& GetPpdReference( const std::string& printer_id) const; + // Mark the printer as not autconfigurable. It is set when the configuration + // of IPP USB printer fails because the printer does not meet the IPP + // Everywhere requirements. + void MarkPrinterAsNotAutoconfigurable(const std::string& printer_id); + + // Returns true <=> the function above was called for |printer_id|. + bool IsMarkedAsNotAutoconfigurable(const std::string& printer_id) const; + private: // Returns true if |printer_id| exists in |printer_state_|. bool PrinterStateExists(const std::string& printer_id) const;
diff --git a/chrome/browser/chromeos/printing/printer_installation_manager.h b/chrome/browser/chromeos/printing/printer_installation_manager.h index c91d6575..c0aee76 100644 --- a/chrome/browser/chromeos/printing/printer_installation_manager.h +++ b/chrome/browser/chromeos/printing/printer_installation_manager.h
@@ -13,9 +13,7 @@ public: virtual ~PrinterInstallationManager() = default; - // Record that the given printers has been installed in CUPS for usage. If - // |printer| is not a saved or enterprise printer, this will have the - // side effect of moving |printer| into the saved class. + // Record that the given printers has been installed in CUPS for usage. // Parameter |is_automatic| should be set to true if the printer was // saved automatically (without requesting additional information // from the user). @@ -24,6 +22,11 @@ // Returns true if |printer| is currently installed in CUPS with this // configuration. virtual bool IsPrinterInstalled(const Printer& printer) const = 0; + + // Record that a requested printer installation failed because the printer + // is not autoconfigurable (does not meet IPP Everywhere requirements). + // This results in shifting the printer from automatic to discovered class. + virtual void PrinterIsNotAutoconfigurable(const Printer& printer) = 0; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printing_stubs.h b/chrome/browser/chromeos/printing/printing_stubs.h index b59dd7c..7f8d61e 100644 --- a/chrome/browser/chromeos/printing/printing_stubs.h +++ b/chrome/browser/chromeos/printing/printing_stubs.h
@@ -29,6 +29,7 @@ void AddObserver(CupsPrintersManager::Observer* observer) override {} void RemoveObserver(CupsPrintersManager::Observer* observer) override {} void PrinterInstalled(const Printer& printer, bool is_automatic) override {} + void PrinterIsNotAutoconfigurable(const Printer& printer) override {} void RecordSetupAbandoned(const Printer& printer) override {} void FetchPrinterStatus(const std::string& printer_id, PrinterStatusCallback cb) override {}
diff --git a/chrome/browser/chromeos/printing/test_printer_configurer.cc b/chrome/browser/chromeos/printing/test_printer_configurer.cc index 4e5cd99..8f722266 100644 --- a/chrome/browser/chromeos/printing/test_printer_configurer.cc +++ b/chrome/browser/chromeos/printing/test_printer_configurer.cc
@@ -16,7 +16,11 @@ void TestPrinterConfigurer::SetUpPrinter(const Printer& printer, PrinterSetupCallback callback) { MarkConfigured(printer.id()); - std::move(callback).Run(PrinterSetupResult::kSuccess); + PrinterSetupResult result = PrinterSetupResult::kSuccess; + if (assigned_results_.count(printer.id())) { + result = assigned_results_[printer.id()]; + } + std::move(callback).Run(result); } bool TestPrinterConfigurer::IsConfigured(const std::string& printer_id) const { @@ -27,4 +31,10 @@ configured_printers_.insert(printer_id); } +void TestPrinterConfigurer::AssignPrinterSetupResult( + const std::string& printer_id, + PrinterSetupResult result) { + assigned_results_[printer_id] = result; +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/test_printer_configurer.h b/chrome/browser/chromeos/printing/test_printer_configurer.h index 475b037..1914d2d 100644 --- a/chrome/browser/chromeos/printing/test_printer_configurer.h +++ b/chrome/browser/chromeos/printing/test_printer_configurer.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "chrome/browser/chromeos/printing/printer_configurer.h" @@ -33,8 +34,12 @@ void MarkConfigured(const std::string& printer_id); + void AssignPrinterSetupResult(const std::string& printer_id, + PrinterSetupResult result); + private: base::flat_set<std::string> configured_printers_; + base::flat_map<std::string, PrinterSetupResult> assigned_results_; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/tpm_firmware_update.cc b/chrome/browser/chromeos/tpm_firmware_update.cc index 0a2d075..e177a8f 100644 --- a/chrome/browser/chromeos/tpm_firmware_update.cc +++ b/chrome/browser/chromeos/tpm_firmware_update.cc
@@ -157,8 +157,8 @@ static void StartOnBackgroundThread( base::FilePathWatcher* watcher, base::FilePathWatcher::Callback watch_callback) { - watcher->Watch(GetUpdateLocationFilePath(), false /* recursive */, - watch_callback); + watcher->Watch(GetUpdateLocationFilePath(), + base::FilePathWatcher::Type::kNonRecursive, watch_callback); watch_callback.Run(base::FilePath(), false /* error */); }
diff --git a/chrome/browser/device_identity/device_oauth2_token_service.cc b/chrome/browser/device_identity/device_oauth2_token_service.cc index cb3b699..c483d391 100644 --- a/chrome/browser/device_identity/device_oauth2_token_service.cc +++ b/chrome/browser/device_identity/device_oauth2_token_service.cc
@@ -18,12 +18,12 @@ #include "chrome/browser/device_identity/device_oauth2_token_store.h" #include "components/policy/proto/device_management_backend.pb.h" #include "components/prefs/pref_service.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" #include "google_apis/gaia/oauth2_access_token_fetcher.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "services/network/public/cpp/shared_url_loader_factory.h" struct DeviceOAuth2TokenService::PendingRequest { @@ -229,8 +229,9 @@ OAuth2AccessTokenConsumer* consumer) { std::string refresh_token = GetRefreshToken(); DCHECK(!refresh_token.empty()); - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory, refresh_token); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory, refresh_token); } bool DeviceOAuth2TokenService::HasRefreshToken(
diff --git a/chrome/browser/devtools/devtools_file_watcher.cc b/chrome/browser/devtools/devtools_file_watcher.cc index 5203156..054985a 100644 --- a/chrome/browser/devtools/devtools_file_watcher.cc +++ b/chrome/browser/devtools/devtools_file_watcher.cc
@@ -131,7 +131,7 @@ return; watchers_[path].reset(new base::FilePathWatcher()); bool success = watchers_[path]->Watch( - path, true, + path, base::FilePathWatcher::Type::kRecursive, base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this))); if (!success) return;
diff --git a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc index d40d576..be45c03 100644 --- a/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc +++ b/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
@@ -189,7 +189,7 @@ base::BlockingType::MAY_BLOCK); base::FilePath brlapi_dir(BRLAPI_SOCKETPATH); if (!file_path_watcher_.Watch( - brlapi_dir, false, + brlapi_dir, base::FilePathWatcher::Type::kNonRecursive, base::Bind(&BrailleControllerImpl::OnSocketDirChangedOnTaskThread, base::Unretained(this)))) { LOG(WARNING) << "Couldn't watch brlapi directory " << BRLAPI_SOCKETPATH;
diff --git a/chrome/browser/media_galleries/gallery_watch_manager.cc b/chrome/browser/media_galleries/gallery_watch_manager.cc index 696f68e..f6ae5b9 100644 --- a/chrome/browser/media_galleries/gallery_watch_manager.cc +++ b/chrome/browser/media_galleries/gallery_watch_manager.cc
@@ -127,8 +127,7 @@ } auto watcher = std::make_unique<base::FilePathWatcher>(); - bool success = watcher->Watch(path, - true /*recursive*/, + bool success = watcher->Watch(path, base::FilePathWatcher::Type::kRecursive, base::Bind(&FileWatchManager::OnFilePathChanged, weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/metrics/startup_metrics_browsertest.cc b/chrome/browser/metrics/startup_metrics_browsertest.cc index 80f46c15..4edaf52 100644 --- a/chrome/browser/metrics/startup_metrics_browsertest.cc +++ b/chrome/browser/metrics/startup_metrics_browsertest.cc
@@ -4,9 +4,11 @@ #include <set> +#include "base/metrics/histogram_base.h" #include "base/metrics/histogram_samples.h" #include "base/metrics/statistics_recorder.h" #include "base/run_loop.h" +#include "base/test/bind.h" #include "build/build_config.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" @@ -45,7 +47,18 @@ // Wait for all histograms to be recorded. The test will hang if an histogram // is not recorded. for (auto* const histogram : kStartupMetrics) { - while (!base::StatisticsRecorder::FindHistogram(histogram)) - base::RunLoop().RunUntilIdle(); + // Continue if histograms was already recorded. + if (base::StatisticsRecorder::FindHistogram(histogram)) + continue; + + // Else, wait until the histogram is recorded. + base::RunLoop run_loop; + base::StatisticsRecorder::SetCallback( + histogram, + base::BindLambdaForTesting( + [&](const char* histogram_name, uint64_t name_hash, + base::HistogramBase::Sample sample) { run_loop.Quit(); })); + run_loop.Run(); + base::StatisticsRecorder::ClearCallback(histogram); } }
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc index bdea464..855850a 100644 --- a/chrome/browser/notifications/notification_platform_bridge_linux.cc +++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -1015,7 +1015,8 @@ // long-running Chrome process. product_logo_file_watcher_ = std::make_unique<base::FilePathWatcher>(); if (!product_logo_file_watcher_->Watch( - product_logo_file_->file_path(), false, + product_logo_file_->file_path(), + base::FilePathWatcher::Type::kNonRecursive, base::Bind( &NotificationPlatformBridgeLinuxImpl::OnProductLogoFileChanged, this))) {
diff --git a/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java index cb72f9c..0e65d8c 100644 --- a/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java +++ b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
@@ -99,8 +99,6 @@ activity.getWindow().setLocalFocus(true, true); TestThreadUtils.runOnUiThreadBlocking(() -> { InstrumentationRegistry.getInstrumentation().callActivityOnRestart(activity); - InstrumentationRegistry.getInstrumentation().callActivityOnStart(activity); - InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity); }); TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index fd694ae..33ab250 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -59,6 +59,7 @@ #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/previews/previews_https_notification_infobar_decider.h" #include "chrome/browser/printing/print_preview_sticky_settings.h" +#include "chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h" #include "chrome/browser/profiles/chrome_version_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_entry.h" @@ -827,6 +828,7 @@ PrefetchProxyOriginDecider::RegisterPrefs(registry); PrefsTabHelper::RegisterProfilePrefs(registry, locale); PreviewsHTTPSNotificationInfoBarDecider::RegisterProfilePrefs(registry); + privacy_sandbox::RegisterProfilePrefs(registry); Profile::RegisterProfilePrefs(registry); ProfileImpl::RegisterProfilePrefs(registry); ProfileNetworkContextService::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.cc b/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.cc new file mode 100644 index 0000000..f4e7273 --- /dev/null +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.cc
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h" + +#include "chrome/common/pref_names.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" + +namespace prefs { + +const char kPrivacySandboxApisEnabled[] = "privacy_sandbox.apis_enabled"; + +const char kPrivacySandboxManauallyControlled[] = + "privacy_sandbox.manually_controlled"; + +} // namespace prefs + +namespace privacy_sandbox { + +void RegisterProfilePrefs(PrefRegistrySimple* registry) { + registry->RegisterBooleanPref(prefs::kPrivacySandboxApisEnabled, false); + registry->RegisterBooleanPref(prefs::kPrivacySandboxManauallyControlled, + false); +} +} // namespace privacy_sandbox
diff --git a/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h b/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h new file mode 100644 index 0000000..60cc44b8 --- /dev/null +++ b/chrome/browser/privacy_sandbox/privacy_sandbox_prefs.h
@@ -0,0 +1,31 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_PREFS_H_ +#define CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_PREFS_H_ + +#include "components/prefs/pref_registry_simple.h" + +namespace prefs { + +// Boolean that is true when Privacy Sandbox APIs are enabled. If the +// PrivacySandboxSettings feature is enabled, this Boolean is controlled by the +// associated UI; if it is disabled, it is controlled by third party cookie +// blocking settings. +extern const char kPrivacySandboxApisEnabled[]; + +// Boolean that indicates if a user has manually toggled the settings associated +// with the PrivacySandboxSettings feature. +extern const char kPrivacySandboxManauallyControlled[]; + +} // namespace prefs + +namespace privacy_sandbox { + +// Registers user preferences related to privacy sandbox. +void RegisterProfilePrefs(PrefRegistrySimple* registry); + +} // namespace privacy_sandbox + +#endif // CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_PREFS_H_
diff --git a/chrome/browser/profiles/profile_browsertest_android.cc b/chrome/browser/profiles/profile_browsertest_android.cc index aa46156..c31fa92 100644 --- a/chrome/browser/profiles/profile_browsertest_android.cc +++ b/chrome/browser/profiles/profile_browsertest_android.cc
@@ -95,7 +95,7 @@ // destroyed between the existence check and when we start watching, if the // order were reversed. EXPECT_TRUE(watcher_->Watch( - watched_file_path_, false /* recursive */, + watched_file_path_, base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&FileDestructionWatcher::OnPathChanged, base::Unretained(this)))); CheckIfPathExists();
diff --git a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java index 22bcb58..250dbd2e 100644 --- a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java +++ b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java
@@ -8,15 +8,17 @@ import android.content.Intent; import android.os.Bundle; import android.support.test.InstrumentationRegistry; -import android.support.test.runner.lifecycle.Stage; +import android.support.test.rule.ActivityTestRule; import androidx.fragment.app.Fragment; +import org.hamcrest.Matchers; import org.junit.Assert; -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.base.test.util.ApplicationTestUtils; - +import org.chromium.base.ActivityState; +import org.chromium.base.ApplicationStatus; +import org.chromium.base.test.util.Criteria; +import org.chromium.base.test.util.CriteriaHelper; /** * Activity test rule that launch {@link SettingsActivity} in tests. * @@ -26,7 +28,7 @@ * @param <T> Fragment that will be attached to the SettingsActivity. */ public class SettingsActivityTestRule<T extends Fragment> - extends BaseActivityTestRule<SettingsActivity> { + extends ActivityTestRule<SettingsActivity> { private final Class<T> mFragmentClass; /** @@ -34,7 +36,16 @@ * @param fragmentClass Fragment that will be attached after the activity starts. */ public SettingsActivityTestRule(Class<T> fragmentClass) { - super(SettingsActivity.class); + this(fragmentClass, false); + } + + /** + * Create the settings activity test rule with an specific fragment class. + * @param fragmentClass Fragment that will be attached after the activity starts. + * @param initialTouchMode Whether in touch mode after the activity starts. + */ + public SettingsActivityTestRule(Class<T> fragmentClass, boolean initialTouchMode) { + super(SettingsActivity.class, initialTouchMode, false); mFragmentClass = fragmentClass; } @@ -56,9 +67,35 @@ SettingsLauncher settingsLauncher = new SettingsLauncherImpl(); Intent intent = settingsLauncher.createSettingsActivityIntent( context, mFragmentClass.getName(), fragmentArgs); - launchActivity(intent); - ApplicationTestUtils.waitForActivityState(getActivity(), Stage.RESUMED); - return getActivity(); + SettingsActivity activity = super.launchActivity(intent); + Assert.assertNotNull(activity); + + return activity; + } + + /** + * We need to ensure that SettingsActivity gets destroyed in the TestRule because sometimes + * it uses the mock signin environment like fake AccountManagerFacade, if the activity starts + * with the stub then it also needs to finish with it. That's why we need to wait till the + * activity state becomes destroyed before tearing down the mock signin environment. + */ + @Override + protected void afterActivityFinished() { + super.afterActivityFinished(); + waitTillActivityIsDestroyed(); + } + + /** + * Block the execution till the SettingsActivity is destroyed. + */ + public void waitTillActivityIsDestroyed() { + SettingsActivity activity = getActivity(); + if (activity != null) { + CriteriaHelper.pollUiThread(() -> { + Criteria.checkThat(ApplicationStatus.getStateForActivity(activity), + Matchers.is(ActivityState.DESTROYED)); + }); + } } /**
diff --git a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc index 60be08c..b4e28848 100644 --- a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc +++ b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
@@ -16,11 +16,13 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/common/webui_url_constants.h" #include "components/signin/public/identity_manager/accounts_cookie_mutator.h" #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" #include "content/public/browser/web_contents.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/google_service_auth_error.h" +#include "url/gurl.h" namespace { @@ -43,8 +45,6 @@ content::WebContents* tab_to_move) : profile_(profile), account_id_(account_id) { Observe(tab_to_move); - if (tab_to_move) - url_to_open_ = tab_to_move->GetURL(); } DiceInterceptedSessionStartupHelper::~DiceInterceptedSessionStartupHelper() = @@ -127,16 +127,15 @@ base::UmaHistogramBoolean("Signin.Intercept.SessionStartupReconcileError", reconcile_error_encountered_); + GURL url_to_open = GURL(chrome::kChromeUINewTabURL); // If the intercepted web contents is still alive, close it now. if (web_contents()) { - // Update the URL once again to catch any potential navigation happening - // while the cookie was updated. - url_to_open_ = web_contents()->GetURL(); + url_to_open = web_contents()->GetURL(); web_contents()->Close(); } // Open a new browser. - NavigateParams params(profile_, url_to_open_, + NavigateParams params(profile_, url_to_open, ui::PAGE_TRANSITION_AUTO_BOOKMARK); Navigate(¶ms);
diff --git a/chrome/browser/signin/dice_intercepted_session_startup_helper.h b/chrome/browser/signin/dice_intercepted_session_startup_helper.h index 77338a9..7b1ebd63 100644 --- a/chrome/browser/signin/dice_intercepted_session_startup_helper.h +++ b/chrome/browser/signin/dice_intercepted_session_startup_helper.h
@@ -13,7 +13,6 @@ #include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/web_contents_observer.h" #include "google_apis/gaia/core_account_id.h" -#include "url/gurl.h" namespace content { class WebContents; @@ -81,7 +80,6 @@ // Timeout while waiting for the account to be added to the cookies in the new // profile. base::CancelableOnceCallback<void()> on_cookie_update_timeout_; - GURL url_to_open_; }; #endif // CHROME_BROWSER_SIGNIN_DICE_INTERCEPTED_SESSION_STARTUP_HELPER_H_
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc index 67ca620e..091d95d 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -38,6 +38,7 @@ #include "content/public/test/browser_test.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" namespace { @@ -421,3 +422,58 @@ nullptr); EXPECT_EQ(GetInterceptorDelegate(profile())->customized_browser(), nullptr); } + +// Close the source tab during the interception and check that the NTP is opened +// in the new profile (regression test for https://crbug.com/1153321). +IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, CloseSourceTab) { + // Setup profile for interception. + identity_test_env()->MakeAccountAvailable("alice@example.com"); + AccountInfo account_info = + identity_test_env()->MakeAccountAvailable("bob@example.com"); + // Fill the account info, in particular for the hosted_domain field. + account_info.full_name = "fullname"; + account_info.given_name = "givenname"; + account_info.hosted_domain = kNoHostedDomainFound; + account_info.locale = "en"; + account_info.picture_url = "https://example.com"; + account_info.is_child_account = false; + DCHECK(account_info.IsValid()); + identity_test_env()->UpdateAccountInfoForAccount(account_info); + + // Add a tab. + GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); + content::WebContents* contents = AddTab(intercepted_url); + int original_tab_count = browser()->tab_strip_model()->count(); + + // Do the signin interception. + ProfileWaiter profile_waiter; + DiceWebSigninInterceptor* interceptor = + DiceWebSigninInterceptorFactory::GetForProfile( + Profile::FromBrowserContext(contents->GetBrowserContext())); + interceptor->MaybeInterceptWebSignin(contents, account_info.account_id, + /*is_new_account=*/true, + /*is_sync_signin=*/false); + // Close the source tab during the profile creation. + contents->Close(); + // Wait for the interception to be complete. + Profile* new_profile = profile_waiter.WaitForProfileAdded(); + ASSERT_TRUE(new_profile); + signin::IdentityManager* new_identity_manager = + IdentityManagerFactory::GetForProfile(new_profile); + EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( + account_info.account_id)); + + // Add the account to the cookies (simulates the account reconcilor). + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); + signin::SetCookieAccounts(new_identity_manager, test_url_loader_factory(), + {{account_info.email, account_info.gaia}}); + + // A browser has been created for the new profile on the new tab page. + ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); + Browser* added_browser = BrowserList::GetInstance()->get(1); + ASSERT_TRUE(added_browser); + EXPECT_EQ(added_browser->profile(), new_profile); + EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); + EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), + GURL("chrome://newtab/")); +}
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc index 797c792..8887744 100644 --- a/chrome/browser/sync/test/integration/password_manager_sync_test.cc +++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -90,7 +90,7 @@ if (!base::PathExists(path_)) { return true; } - watcher_.Watch(path_, /*recursive=*/true, + watcher_.Watch(path_, base::FilePathWatcher::Type::kRecursive, base::BindRepeating(&PathDeletionWaiter::PathChanged, base::Unretained(this))); run_loop_.Run();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 08594c3..50448acd 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -5,6 +5,7 @@ import("//build/config/buildflags_paint_preview.gni") import("//build/config/chromecast_build.gni") import("//build/config/chromeos/ui_mode.gni") +import("//build/config/chromeos/ui_mode.gni") import("//build/config/compiler/compiler.gni") import("//build/config/crypto.gni") import("//build/config/features.gni") @@ -36,7 +37,7 @@ "app_list/app_list_util.cc", "app_list/app_list_util.h", - # All other browser/ui/app_list files go under is_chromeos below. + # All other browser/ui/app_list files go under is_chromeos_ash below. "autofill/autofill_bubble_handler.h", "autofill/autofill_popup_controller.h", "autofill/autofill_popup_controller_impl.cc", @@ -1569,14 +1570,14 @@ ] public_deps += [ "//ui/base/dragdrop/mojom:mojom_headers" ] - if (use_ozone && !is_chromeos) { + if (use_ozone && !is_chromeos_ash) { deps += [ "//ui/base:features", "//ui/ozone", ] } - if (is_linux && !is_chromeos) { + if (is_linux || is_chromeos_lacros) { deps += [ "//ui/base/ime/linux" ] } @@ -1619,7 +1620,7 @@ deps += [ "//chrome/browser/supervised_user/supervised_user_error_page" ] } - if (is_chromeos) { + if (is_chromeos_ash) { assert(enable_extensions) assert(enable_supervised_users) assert(toolkit_views) @@ -2830,7 +2831,7 @@ deps += [ "//ui/webui" ] } - if (is_win || is_mac || is_linux) { + if (is_win || is_mac || (is_linux || is_chromeos_lacros)) { sources += [ "bookmarks/bookmark_bubble_sign_in_delegate.cc", "bookmarks/bookmark_bubble_sign_in_delegate.h", @@ -3256,7 +3257,7 @@ } } - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "views/apps/chrome_app_window_client_views_linux.cc", "views/first_run_dialog.cc", @@ -3313,7 +3314,7 @@ ] } if (use_ozone) { - if (!is_linux) { + if (!is_linux || is_chromeos_lacros) { sources += [ "views/frame/browser_desktop_window_tree_host_platform.cc", "views/frame/browser_desktop_window_tree_host_platform.h", @@ -3321,7 +3322,7 @@ } sources += [ "views/frame/native_browser_frame_factory_ozone.cc" ] } - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "views/frame/browser_desktop_window_tree_host_linux.cc", "views/frame/browser_desktop_window_tree_host_linux.h", @@ -4164,7 +4165,7 @@ allow_circular_includes_from += [ "//chrome/browser/ui/views" ] - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "views/chrome_views_delegate_linux.cc", "views/frame/desktop_linux_browser_frame_view.cc", @@ -4216,7 +4217,7 @@ sources += [ "views/chrome_views_delegate_win.cc" ] } - if (is_win || is_linux) { + if (is_win || (is_linux || is_chromeos_lacros)) { sources += [ "views/native_widget_factory.cc", "views/native_widget_factory.h", @@ -4225,7 +4226,7 @@ if (use_aura) { # These files can do Gtk+-based theming for builds with gtk enabled. - if (is_linux) { + if (is_linux || is_chromeos_lacros) { sources += [ "views/chrome_browser_main_extra_parts_views_linux.cc", "views/chrome_browser_main_extra_parts_views_linux.h", @@ -4248,7 +4249,7 @@ } } - if (!is_chromeos) { + if (!is_chromeos_ash) { sources += [ "views/accessibility/accessibility_focus_highlight.cc", "views/accessibility/accessibility_focus_highlight.h", @@ -4320,12 +4321,12 @@ "//ui/wm", ] - if (!is_chromeos && !chromeos_is_browser_only) { + if (!is_chromeos_ash && !is_chromeos_lacros) { sources += [ "views/frame/browser_non_client_frame_view_factory_views.cc" ] } - if (!is_chromeos) { + if (!is_chromeos_ash) { sources += [ "views/frame/desktop_browser_frame_aura.cc", "views/frame/desktop_browser_frame_aura.h", @@ -4514,7 +4515,7 @@ "//services/device/public/mojom:usb", ] - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "webui/print_preview/local_printer_handler_chromeos.cc", "webui/print_preview/local_printer_handler_chromeos.h", @@ -4532,7 +4533,7 @@ "webui/print_preview/privet_printer_handler.h", ] - if (!is_chromeos) { + if (!is_chromeos_ash) { deps += [ "//chrome/common:service_process_mojom" ] } } @@ -4728,7 +4729,7 @@ ] } - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "ash/ash_test_util.cc", "ash/ash_test_util.h", @@ -4759,7 +4760,7 @@ } } -if (is_chromeos) { +if (is_chromeos_ash) { source_set("ash_test_support") { check_includes = false sources = [
diff --git a/chrome/browser/ui/android/external_protocol_dialog_android.cc b/chrome/browser/ui/android/external_protocol_dialog_android.cc index 21626b8d..d4202125 100644 --- a/chrome/browser/ui/android/external_protocol_dialog_android.cc +++ b/chrome/browser/ui/android/external_protocol_dialog_android.cc
@@ -28,6 +28,9 @@ navigation_interception::NavigationParams navigation_params( url, content::Referrer(), + // Pass 0 as the navigation ID to specify that this instance doesn't + // correspond to a NavigationHandle. + 0, has_user_gesture, // has_user_gesture false, // is_post, doesn't matter here. page_transition,
diff --git a/chrome/browser/ui/app_list/app_list_util.cc b/chrome/browser/ui/app_list/app_list_util.cc index dfa3698..61c8575 100644 --- a/chrome/browser/ui/app_list/app_list_util.cc +++ b/chrome/browser/ui/app_list/app_list_util.cc
@@ -5,9 +5,10 @@ #include "chrome/browser/ui/app_list/app_list_util.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" bool IsAppLauncherEnabled() { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return true; #else return false;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 267cc42..05c976c1 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -27,6 +27,7 @@ #include "base/test/scoped_command_line.h" #include "base/values.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_icon_factory.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -2922,7 +2923,7 @@ } // TODO(crbug.com/1005069) Disabled on Chrome OS due to flake -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_IconLoadNonSupportedScales DISABLED_IconLoadNonSupportedScales #else #define MAYBE_IconLoadNonSupportedScales IconLoadNonSupportedScales
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.cc b/chrome/browser/ui/app_list/chrome_app_list_item.cc index faf376a..926c539b 100644 --- a/chrome/browser/ui/app_list/chrome_app_list_item.cc +++ b/chrome/browser/ui/app_list/chrome_app_list_item.cc
@@ -7,6 +7,7 @@ #include <utility> #include "ash/public/cpp/tablet_mode.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/app_list_client_impl.h" #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" @@ -16,7 +17,7 @@ #include "ui/gfx/color_utils.h" #include "ui/gfx/image/image_skia_operations.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" #endif @@ -83,7 +84,7 @@ } void ChromeAppListItem::PerformActivate(int event_flags) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Handle recording app launch source from the AppList in Demo Mode. chromeos::DemoSession::RecordAppLaunchSourceIfInDemoMode( chromeos::DemoSession::AppLaunchSource::kAppList);
diff --git a/chrome/browser/ui/apps/app_info_dialog.h b/chrome/browser/ui/apps/app_info_dialog.h index 5efbf77..8711dd3 100644 --- a/chrome/browser/ui/apps/app_info_dialog.h +++ b/chrome/browser/ui/apps/app_info_dialog.h
@@ -8,8 +8,9 @@ #include <string> #include "base/callback_forward.h" +#include "build/chromeos_buildflags.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ui/gfx/native_widget_types.h" #endif @@ -43,7 +44,7 @@ // Returns true if the app info dialog is available for an app. bool CanShowAppInfoDialog(Profile* profile, const std::string& extension_id); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Shows the chrome app information as a frameless window for the given |app| // and |profile| at the given |app_info_bounds|. void ShowAppInfoInAppList(gfx::NativeWindow parent,
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc index 8188dc0c..7117c6e 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.cc +++ b/chrome/browser/ui/apps/chrome_app_delegate.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/macros.h" #include "base/strings/stringprintf.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/apps/platform_apps/audio_focus_web_contents_observer.h" #include "chrome/browser/chrome_notification_types.h" @@ -49,7 +50,7 @@ #include "printing/buildflags/buildflags.h" #include "services/service_manager/public/cpp/interface_provider.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h" #endif @@ -310,7 +311,7 @@ } int ChromeAppDelegate::PreferredIconSize() const { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Use a size appropriate for the ash shelf (see ash::kShelfSize). return extension_misc::EXTENSION_ICON_MEDIUM; #else @@ -369,7 +370,7 @@ bool reverse) { if (!for_lock_screen_app_) return false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return lock_screen_apps::StateController::Get()->HandleTakeFocus(web_contents, reverse); #else
diff --git a/chrome/browser/ui/apps/chrome_app_window_client.cc b/chrome/browser/ui/apps/chrome_app_window_client.cc index 09c7e00a..53acdc1 100644 --- a/chrome/browser/ui/apps/chrome_app_window_client.cc +++ b/chrome/browser/ui/apps/chrome_app_window_client.cc
@@ -9,6 +9,7 @@ #include "base/memory/singleton.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/devtools/devtools_window.h" #include "components/version_info/version_info.h" #include "content/public/browser/devtools_agent_host.h" @@ -16,7 +17,7 @@ #include "extensions/common/extension.h" #include "extensions/common/features/feature_channel.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h" #endif @@ -55,7 +56,7 @@ content::BrowserContext* context, const extensions::Extension* extension, extensions::api::app_runtime::ActionType action) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) auto app_delegate = std::make_unique<ChromeAppDelegate>(true /*keep_alive*/); app_delegate->set_for_lock_screen_app(true);
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc index b2b3fc68..06c9849 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -27,6 +27,7 @@ #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/file_manager/open_util.h" @@ -433,7 +434,7 @@ return; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) SYSLOG(INFO) << "Screenshot taken"; #endif
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc index 74b98cf..5edb638 100644 --- a/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc +++ b/chrome/browser/ui/ash/holding_space/holding_space_file_system_delegate.cc
@@ -38,7 +38,7 @@ return; watchers_[file_path] = std::make_unique<base::FilePathWatcher>(); watchers_[file_path]->Watch( - file_path, /*recursive=*/false, + file_path, base::FilePathWatcher::Type::kNonRecursive, base::Bind(&FileSystemWatcher::OnFilePathChanged, weak_factory_.GetWeakPtr())); }
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc index 58e49ef..e0d00ed 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/no_destructor.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/crash/core/common/crash_key.h" #include "ui/accessibility/aura/aura_window_properties.h" #include "ui/accessibility/ax_action_data.h" @@ -29,7 +30,7 @@ #include "ui/views/view.h" #include "ui/views/widget/widget.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/wm/window_util.h" @@ -45,7 +46,7 @@ enabled_ = true; Reset(false); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Seed the views::AXAuraObjCache with per-display root windows so // GetTopLevelWindows() returns the correct values when automation is enabled // with multiple displays connected. @@ -62,7 +63,7 @@ // ordering of two base::Singletons. cache_->SetDelegate(this); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) aura::Window* active_window = ash::window_util::GetActiveWindow(); if (active_window) { views::AXAuraObjWrapper* focus = cache_->GetOrCreate(active_window); @@ -162,7 +163,7 @@ } else { current_tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(current_tree_.get()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ash::Shell* shell = ash::Shell::Get(); // Windows within the overlay container get moved to the new monitor when // the primary display gets swapped. @@ -170,7 +171,7 @@ shell->GetContainer(shell->GetPrimaryRootWindow(), ash::kShellWindowId_OverlayContainer), cache_.get()); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } } @@ -248,7 +249,7 @@ void AutomationManagerAura::PerformHitTest( const ui::AXActionData& original_action) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ui::AXActionData action = original_action; aura::Window* root_window = ash::Shell::Get()->GetPrimaryRootWindow(); if (!root_window)
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index 7b247d30..9d59f8a 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -11,6 +11,7 @@ #include "base/optional.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/accessibility/accessibility_state_utils.h" #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "chrome/browser/ui/autofill/autofill_popup_view.h" @@ -37,7 +38,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/text_utils.h" -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "content/public/browser/browser_accessibility_state.h" #endif @@ -281,7 +282,7 @@ NiceMock<TestAutofillPopupController>* autofill_popup_controller_; }; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) class AutofillPopupControllerAccessibilityUnitTest : public AutofillPopupControllerUnitTest { public: @@ -700,7 +701,7 @@ Mock::VerifyAndClearExpectations(autofill_popup_view()); } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(AutofillPopupControllerAccessibilityUnitTest, FireControlsChangedEvent) { StrictMock<MockAxPlatformNodeDelegate> mock_ax_platform_node_delegate; StrictMock<MockAxPlatformNode> mock_ax_platform_node;
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index 19d2688..b6e1182 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/history/history_test_utils.h" #include "chrome/browser/policy/profile_policy_connector_builder.h" @@ -270,7 +271,8 @@ } // TODO(crbug.com/1115886): Flaky on Mac ASAN and Chrome OS. -#if (defined(OS_MAC) && defined(ADDRESS_SANITIZER)) || defined(OS_CHROMEOS) +#if (defined(OS_MAC) && defined(ADDRESS_SANITIZER)) || \ + BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_BlockWebContentsCreationIncognito \ DISABLED_BlockWebContentsCreationIncognito #else
diff --git a/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc index 056e83f..5b2c9ce 100644 --- a/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_tracker_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/supports_user_data.h" #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/test_safe_browsing_database_helper.h" #include "chrome/browser/ui/browser.h" @@ -573,7 +574,7 @@ } // TODO(crbug.com/1146598): Test is flaky on Lacros. -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) #define MAYBE_PopupNoRedirect_RedirectCountZero DISABLED_PopupNoRedirect_RedirectCountZero #else #define MAYBE_PopupNoRedirect_RedirectCountZero PopupNoRedirect_RedirectCountZero
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc index 54bd8b3..7cfdf44 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc
@@ -10,6 +10,7 @@ #include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/net/referrer.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h" @@ -20,11 +21,11 @@ #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h" #include "chrome/common/webui_url_constants.h" -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace { @@ -108,7 +109,7 @@ } void BluetoothChooserController::OpenAdapterOffHelpUrl() const { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Chrome OS can directly link to the OS setting to turn on the adapter. chrome::SettingsWindowManager::GetInstance()->ShowOSSettings( GetBrowser()->profile(),
diff --git a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc index c03e0503..c308f84 100644 --- a/chrome/browser/ui/bookmarks/bookmark_browsertest.cc +++ b/chrome/browser/ui/bookmarks/bookmark_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" @@ -155,7 +156,7 @@ ASSERT_EQ(base::ASCIIToUTF16(kPersistBookmarkTitle), urls[0].title); } -#if !defined(OS_CHROMEOS) // No multi-profile on ChromeOS. +#if !BUILDFLAG(IS_CHROMEOS_ASH) // No multi-profile on ChromeOS. // Sanity check that bookmarks from different profiles are separate. // DISABLED_ because it regularly times out: http://crbug.com/159002. @@ -318,7 +319,7 @@ // ChromeOS initializes two profiles (Default and test-user) and it's impossible // to distinguish UMA samples separately. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(BookmarkBrowsertest, PRE_EmitUmaForDuplicates) { BookmarkModel* bookmark_model = WaitForBookmarkModel(browser()->profile()); @@ -384,4 +385,4 @@ testing::ElementsAre(base::Bucket(/*min=*/6, /*count=*/1))); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc b/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc index e8240497..1d15141f 100644 --- a/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc +++ b/chrome/browser/ui/bookmarks/bookmark_tab_helper.cc
@@ -6,6 +6,7 @@ #include "base/observer_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/defaults.h" #include "chrome/browser/profiles/profile.h" @@ -58,7 +59,7 @@ Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile()) return false; #endif
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils.cc b/chrome/browser/ui/bookmarks/bookmark_utils.cc index c750eaf..d24185e7 100644 --- a/chrome/browser/ui/bookmarks/bookmark_utils.cc +++ b/chrome/browser/ui/bookmarks/bookmark_utils.cc
@@ -10,6 +10,7 @@ #include "base/notreached.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" @@ -142,7 +143,7 @@ if (profile->IsLegacySupervised()) return false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Chrome OS uses the app list / app launcher. return false; #else
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index ef1c039..3dd7a7f 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -31,6 +31,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" @@ -246,7 +247,7 @@ #include "ui/base/win/shell.h" #endif // defined(OS_WIN) -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "components/session_manager/core/session_manager.h" #endif @@ -320,7 +321,7 @@ } bool IsOnKioskSplashScreen() { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) session_manager::SessionManager* session_manager = session_manager::SessionManager::Get(); if (!session_manager) @@ -1360,7 +1361,7 @@ bool Browser::CanDragEnter(content::WebContents* source, const content::DropData& data, blink::DragOperationsMask operations_allowed) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Disallow drag-and-drop navigation for Settings windows which do not support // external navigation. if ((operations_allowed & blink::kDragOperationLink) && @@ -1505,11 +1506,11 @@ } bool Browser::ShouldShowStaleContentOnEviction(content::WebContents* source) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return source == tab_strip_model_->GetActiveWebContents(); #else return false; -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } bool Browser::IsFrameLowPriority( @@ -2727,7 +2728,7 @@ // Browser, In-progress download termination handling (private): bool Browser::CanCloseWithInProgressDownloads() { -#if defined(OS_MAC) || defined(OS_CHROMEOS) +#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) // On Mac and ChromeOS, non-incognito and non-Guest downloads can still // continue after window is closed. if (!profile_->IsOffTheRecord() && !profile_->IsEphemeralGuestProfile()) @@ -2934,7 +2935,7 @@ } } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // TODO(b/64863368): Consider Fullscreen mode. bool Browser::CustomTabBrowserSupportsWindowFeature( WindowFeature feature) const { @@ -2966,7 +2967,7 @@ case TYPE_DEVTOOLS: case TYPE_APP_POPUP: return AppPopupBrowserSupportsWindowFeature(feature, check_can_support); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case TYPE_CUSTOM_TAB: return CustomTabBrowserSupportsWindowFeature(feature); #endif
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index afd85299..9c880452 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -21,6 +21,7 @@ #include "base/strings/string16.h" #include "base/timer/elapsed_timer.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/devtools/devtools_toggle_action.h" #include "chrome/browser/ui/bookmarks/bookmark_bar.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper_observer.h" @@ -137,7 +138,7 @@ // AppBrowserController) but looks like a popup (e.g. it never has a tab // strip). TYPE_APP_POPUP, -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Browser for ARC++ Chrome custom tabs. // It's an enhanced version of TYPE_POPUP, and is used to show the Chrome // Custom Tab toolbar for ARC++ apps. It has UI customizations like using @@ -640,7 +641,7 @@ bool is_type_app() const { return type_ == TYPE_APP; } bool is_type_app_popup() const { return type_ == TYPE_APP_POPUP; } bool is_type_devtools() const { return type_ == TYPE_DEVTOOLS; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) bool is_type_custom_tab() const { return type_ == TYPE_CUSTOM_TAB; } #endif // TODO(crbug.com/990158): |deprecated_is_app()| is added for backwards @@ -1038,7 +1039,7 @@ bool AppBrowserSupportsWindowFeature(WindowFeature feature, bool check_can_support) const; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) bool CustomTabBrowserSupportsWindowFeature(WindowFeature feature) const; #endif
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index 72fd3d8d..97c05d0 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -27,6 +27,7 @@ #include "base/test/metrics/user_action_tester.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" @@ -1024,7 +1025,7 @@ // everything but ChromeOS allows unload handlers to block exit. On that // platform, though, it exits unconditionally. See the comment and bug ID // in AttemptUserExit() in application_lifetime.cc. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) chrome::AttemptExit(); #else chrome::ExecuteCommand(second_window, IDC_EXIT); @@ -1461,7 +1462,7 @@ // Chromeos defaults to restoring the last session, so this test isn't // applicable. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Makes sure pinned tabs are restored correctly on start. IN_PROC_BROWSER_TEST_F(BrowserTest, RestorePinnedTabs) { ASSERT_TRUE(embedded_test_server()->Start()); @@ -1517,13 +1518,13 @@ EXPECT_TRUE(new_model->IsTabPinned(1)); EXPECT_FALSE(new_model->IsTabPinned(2)); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) // TODO(1126339): fix the way how exo creates accelerated widgets. At the // moment, they are created only after the client attaches a buffer to a surface, // which is incorrect and results in the "[destroyed object]: error 1: popup // parent not constructed" error. -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) #define MAYBE_CloseWithAppMenuOpen DISABLED_CloseWithAppMenuOpen #else #define MAYBE_CloseWithAppMenuOpen CloseWithAppMenuOpen @@ -1693,7 +1694,7 @@ EXPECT_TRUE(new_command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW)); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(BrowserTest, ArcBrowserWindowFeaturesSetCorrectly) { Browser* new_browser = Browser::Create( Browser::CreateParams(Browser::TYPE_CUSTOM_TAB, browser()->profile(), @@ -2039,13 +2040,15 @@ // TODO(linux_aura) http://crbug.com/163931 // Mac disabled: http://crbug.com/169820 -#if !defined(OS_MAC) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if !defined(OS_MAC) && !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) IN_PROC_BROWSER_TEST_F(BrowserTest, FullscreenBookmarkBar) { chrome::ToggleBookmarkBar(browser()); EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state()); chrome::ToggleFullscreenMode(browser()); EXPECT_TRUE(browser()->window()->IsFullscreen()); -#if defined(OS_MAC) || defined(OS_CHROMEOS) +#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) // Mac and Chrome OS both have an "immersive style" fullscreen where the // bookmark bar is visible when the top views slide down. EXPECT_EQ(BookmarkBar::SHOW, browser()->bookmark_bar_state()); @@ -2077,7 +2080,9 @@ } }; -#if defined(OS_MAC) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_MAC) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) // Mac: http://crbug.com/103912 // Linux: http://crbug.com/163931 #define MAYBE_EnableKioskModeTest DISABLED_EnableKioskModeTest @@ -2212,7 +2217,7 @@ // Chromeos needs to track app windows because it considers them to be part of // session state. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(NoStartupWindowTest, DontInitSessionServiceForApps) { Profile* profile = ProfileManager::GetActiveUserProfile(); @@ -2226,7 +2231,7 @@ ASSERT_FALSE(ProcessedAnyCommands(command_storage_manager)); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) // This test needs to be placed outside the anonymous namespace because we // need to access private type of Browser.
diff --git a/chrome/browser/ui/browser_close_unittest.cc b/chrome/browser/ui/browser_close_unittest.cc index b2e2d8e..bba07bfd 100644 --- a/chrome/browser/ui/browser_close_unittest.cc +++ b/chrome/browser/ui/browser_close_unittest.cc
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/download/chrome_download_manager_delegate.h" #include "chrome/browser/download/download_core_service.h" #include "chrome/browser/download/download_core_service_factory.h" @@ -264,7 +265,7 @@ EXPECT_EQ(Browser::DownloadCloseType::kBrowserShutdown, browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking)); EXPECT_EQ(num_downloads_blocking, 1); -#if defined(OS_MAC) || defined(OS_CHROMEOS) +#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_EQ(true, browser->CanCloseWithInProgressDownloads()); #else EXPECT_EQ(false, browser->CanCloseWithInProgressDownloads());
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index 0ee1abae..5fb8de1 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -17,6 +17,7 @@ #include "base/stl_util.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" @@ -76,14 +77,16 @@ #include "content/public/browser/gpu_data_manager.h" #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/platform_util.h" #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h" #include "chrome/browser/ui/browser_commands_chromeos.h" #include "components/session_manager/core/session_manager.h" #endif -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h" #endif @@ -211,7 +214,7 @@ if (browser_->is_type_app() || browser_->is_type_app_popup()) return false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // On Chrome OS, the top row of keys are mapped to browser actions like // back/forward or refresh. We don't want web pages to be able to change the // behavior of these keys. Ash handles F4 and up; this leaves us needing to @@ -247,7 +250,9 @@ #endif } -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) // If this key was registered by the user as a content editing hotkey, then // it is not reserved. ui::TextEditKeyBindingsDelegateAuraLinux* delegate = @@ -280,7 +285,7 @@ UpdateCommandsForFullscreenMode(); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) void BrowserCommandController::LockedFullscreenStateChanged() { UpdateCommandsForLockedFullscreenMode(); } @@ -468,7 +473,7 @@ PromptToNameWindow(browser_); break; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case IDC_VISIT_DESKTOP_OF_LRU_USER_2: case IDC_VISIT_DESKTOP_OF_LRU_USER_3: case IDC_VISIT_DESKTOP_OF_LRU_USER_4: @@ -477,7 +482,9 @@ break; #endif -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) case IDC_MINIMIZE_WINDOW: browser_->window()->Minimize(); break; @@ -661,7 +668,7 @@ case IDC_TASK_MANAGER: OpenTaskManager(browser_); break; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case IDC_TAKE_SCREENSHOT: TakeScreenshot(); break; @@ -739,7 +746,7 @@ case IDC_TOGGLE_COMMANDER: ToggleCommander(browser_); break; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) case IDC_SHOW_SIGNIN: ShowBrowserSigninOrSettings( browser_, signin_metrics::AccessPoint::ACCESS_POINT_MENU); @@ -935,7 +942,7 @@ command_updater_.UpdateCommandEnabled(IDC_EXIT, true); command_updater_.UpdateCommandEnabled(IDC_DEBUG_FRAME_TOGGLE, true); command_updater_.UpdateCommandEnabled(IDC_NAME_WINDOW, true); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true); // The VisitDesktop command is only supported for up to 5 logged in users // because that's the max number of user sessions. If that number is increased @@ -951,7 +958,9 @@ command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_4, true); command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_5, true); #endif -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true); command_updater_.UpdateCommandEnabled(IDC_MAXIMIZE_WINDOW, true); command_updater_.UpdateCommandEnabled(IDC_RESTORE_WINDOW, true); @@ -1004,7 +1013,7 @@ IDC_CLEAR_BROWSING_DATA, (!profile()->IsGuestSession() && !profile()->IsSystemProfile() && !profile()->IsIncognitoProfile())); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) command_updater_.UpdateCommandEnabled(IDC_TAKE_SCREENSHOT, true); // Chrome OS uses the system tray menu to handle multi-profiles. Avatar menu // is only required in incognito mode. @@ -1027,7 +1036,7 @@ IDC_HOME, normal_window || browser_->deprecated_is_app()); const bool is_web_app_or_custom_tab = -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) browser_->is_type_custom_tab() || #endif web_app::AppBrowserController::IsForWebAppBrowser(browser_); @@ -1371,7 +1380,7 @@ command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, has_toolbar); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) namespace { #if DCHECK_IS_ON()
diff --git a/chrome/browser/ui/browser_command_controller.h b/chrome/browser/ui/browser_command_controller.h index 381be31e..b249f01 100644 --- a/chrome/browser/ui/browser_command_controller.h +++ b/chrome/browser/ui/browser_command_controller.h
@@ -9,6 +9,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/command_updater.h" #include "chrome/browser/command_updater_delegate.h" #include "chrome/browser/command_updater_impl.h" @@ -50,7 +51,7 @@ void ZoomStateChanged(); void ContentRestrictionsChanged(); void FullscreenStateChanged(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Called when the browser goes in or out of the special locked fullscreen // mode. In this mode the user is basically locked into the current browser // window and tab hence we disable most keyboard shortcuts and we also @@ -156,7 +157,7 @@ // app windows. void UpdateCommandsForHostedAppAvailability(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Update commands whose state depends on whether the window is in locked // fullscreen mode or not. void UpdateCommandsForLockedFullscreenMode();
diff --git a/chrome/browser/ui/browser_command_controller_browsertest.cc b/chrome/browser/ui/browser_command_controller_browsertest.cc index 67780d1..7da7d58 100644 --- a/chrome/browser/ui/browser_command_controller_browsertest.cc +++ b/chrome/browser/ui/browser_command_controller_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/run_loop.h" #include "base/stl_util.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" @@ -33,7 +34,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chromeos/constants/chromeos_switches.h" #include "chromeos/ui/base/window_pin_type.h" #include "chromeos/ui/base/window_properties.h" @@ -48,7 +49,7 @@ ~BrowserCommandControllerBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) command_line->AppendSwitch( chromeos::switches::kIgnoreUserProfileMappingForTests); #endif @@ -86,7 +87,7 @@ } // TODO(https://crbug.com/1125474): Expand to cover ChromeOS. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) class GuestBrowserCommandControllerBrowserTest : public BrowserCommandControllerBrowserTest, public testing::WithParamInterface<bool> { @@ -116,7 +117,7 @@ /*is_ephemeral=*/testing::Bool()); #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(BrowserCommandControllerBrowserTest, LockedFullscreen) { CommandUpdaterImpl* command_updater = &browser()->command_controller()->command_updater_;
diff --git a/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc index 3d6ce45c..5fc3ec48 100644 --- a/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc +++ b/chrome/browser/ui/browser_command_controller_interactive_browsertest.cc
@@ -4,6 +4,7 @@ #include "base/macros.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/fullscreen_keyboard_browsertest_base.h" #include "chrome/test/base/in_process_browser_test.h" @@ -149,7 +150,7 @@ // the page to exit fullscreen mode. So we need to maintain a list of exiting / // non-exiting commands, which is not the goal of this test. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // This test is flaky on ChromeOS, see http://crbug.com/754878. #define MAYBE_ShortcutsShouldTakeEffectInJsFullscreen \ DISABLED_ShortcutsShouldTakeEffectInJsFullscreen
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc index 18ad928..d108766 100644 --- a/chrome/browser/ui/browser_command_controller_unittest.cc +++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -8,6 +8,7 @@ #include "base/stl_util.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/command_updater.h" @@ -52,7 +53,7 @@ }; TEST_F(BrowserCommandControllerTest, IsReservedCommandOrKey) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // F1-3 keys are reserved Chrome accelerators on Chrome OS. EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey( IDC_BACK, content::NativeWebKeyboardEvent( @@ -109,7 +110,7 @@ -1, content::NativeWebKeyboardEvent(ui::KeyEvent( ui::ET_KEY_PRESSED, ui::VKEY_F3, ui::DomCode::F3, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)))); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(USE_AURA) // Ctrl+n, Ctrl+w are reserved while Ctrl+f is not. @@ -142,7 +143,7 @@ ASSERT_TRUE(browser()->is_type_app()); // When is_type_app(), no keys are reserved. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey( IDC_BACK, content::NativeWebKeyboardEvent(ui::KeyEvent( ui::ET_KEY_PRESSED, ui::VKEY_F1, ui::DomCode::F1, 0)))); @@ -155,7 +156,7 @@ EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey( -1, content::NativeWebKeyboardEvent(ui::KeyEvent( ui::ET_KEY_PRESSED, ui::VKEY_F4, ui::DomCode::F4, 0)))); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(USE_AURA) // The content::NativeWebKeyboardEvent constructor is available only when @@ -228,7 +229,7 @@ bool enabled = true; size_t profiles_count = 1U; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Chrome OS uses system tray menu to handle multi-profiles. enabled = false; profiles_count = 2U;
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h index c95dcf7..bf5394f 100644 --- a/chrome/browser/ui/browser_dialogs.h +++ b/chrome/browser/ui/browser_dialogs.h
@@ -14,6 +14,7 @@ #include "base/optional.h" #include "base/strings/string16.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/bookmarks/bookmark_editor.h" #include "chrome/common/buildflags.h" #include "content/public/browser/content_browser_client.h" @@ -149,7 +150,7 @@ // user interaction. void SetAutoAcceptPWAInstallConfirmationForTesting(bool auto_accept); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Shows the print job confirmation dialog bubble anchored to the toolbar icon // for the extension. @@ -164,7 +165,7 @@ const base::string16& printer_name, base::OnceCallback<void(bool)> callback); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_MAC)
diff --git a/chrome/browser/ui/browser_finder.cc b/chrome/browser/ui/browser_finder.cc index 818076d..ecace6de 100644 --- a/chrome/browser/ui/browser_finder.cc +++ b/chrome/browser/ui/browser_finder.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" @@ -20,7 +21,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/multi_user_window_manager.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h" @@ -39,7 +40,7 @@ const uint32_t kMatchCanSupportWindowFeature = 1 << 1; const uint32_t kMatchNormal = 1 << 2; const uint32_t kMatchDisplayId = 1 << 3; -#if defined(OS_WIN) || defined(OS_CHROMEOS) +#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) const uint32_t kMatchCurrentWorkspace = 1 << 4; #endif @@ -61,7 +62,7 @@ return false; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Get the profile on which the window is currently shown. // MultiUserWindowManagerHelper might be NULL under test scenario. ash::MultiUserWindowManager* const multi_user_window_manager = @@ -82,7 +83,7 @@ if (browser->profile()->GetOriginalProfile() != profile->GetOriginalProfile()) return false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (shown_profile && shown_profile->GetOriginalProfile() != profile->GetOriginalProfile()) { return false; @@ -91,7 +92,7 @@ } else { if (browser->profile() != profile) return false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (shown_profile && shown_profile != profile) return false; #endif @@ -100,7 +101,7 @@ if ((match_types & kMatchNormal) && !browser->is_type_normal()) return false; -#if defined(OS_WIN) || defined(OS_CHROMEOS) +#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) // Note that |browser->window()| might be nullptr in tests. if ((match_types & kMatchCurrentWorkspace) && (!browser->window() || !browser->window()->IsOnCurrentWorkspace())) { @@ -150,7 +151,7 @@ match_types |= kMatchOriginalProfile; if (display_id != display::kInvalidDisplayId) match_types |= kMatchDisplayId; -#if defined(OS_WIN) || defined(OS_CHROMEOS) +#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) if (match_current_workspace) match_types |= kMatchCurrentWorkspace; #endif
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc index 9e33691..6f46f6b 100644 --- a/chrome/browser/ui/browser_navigator.cc +++ b/chrome/browser/ui/browser_navigator.cc
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_about_handler.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/platform_util.h" @@ -49,7 +50,7 @@ #include "extensions/buildflags/buildflags.h" #include "url/url_constants.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/multi_user_window_manager.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h" #include "chrome/browser/ui/settings_window_manager_chromeos.h" @@ -540,7 +541,7 @@ ShowSingletonTabOverwritingNTP(params->browser, std::move(*params)); return; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (source_browser) { // Open OS settings in PWA, even when user types in URL bar. if (params->url.GetOrigin() == @@ -765,7 +766,7 @@ // chrome://settings. return host != chrome::kChromeUIAppLauncherPageHost && host != chrome::kChromeUISettingsHost && -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) host != chrome::kChromeUIOSSettingsHost && #endif host != chrome::kChromeUIHelpHost &&
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc index 52d65d7..9949e00c 100644 --- a/chrome/browser/ui/browser_navigator_browsertest.cc +++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" @@ -1409,7 +1410,7 @@ } // TODO(1024166): Timing out on linux-chromeos-dbg. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_NavigateFromBlankToOptionsInSameTab \ DISABLED_NavigateFromBlankToOptionsInSameTab #else @@ -1435,7 +1436,7 @@ } // TODO(1024166): Timing out on linux-chromeos-dbg. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_NavigateFromNTPToOptionsInSameTab \ DISABLED_NavigateFromNTPToOptionsInSameTab #else @@ -1514,7 +1515,7 @@ } // TODO(1024166): Timing out on linux-chromeos-dbg. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_NavigateFromNTPToOptionsPageInSameTab \ DISABLED_NavigateFromNTPToOptionsPageInSameTab #else @@ -1605,7 +1606,7 @@ } // TODO(1024166): Timing out on linux-chromeos-dbg. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_CloseSingletonTab DISABLED_CloseSingletonTab #else #define MAYBE_CloseSingletonTab CloseSingletonTab @@ -1651,7 +1652,7 @@ } // TODO(linux_aura) http://crbug.com/163931 -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) +#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_AURA) #define MAYBE_NavigateFromDefaultToBookmarksInSameTab \ DISABLED_NavigateFromDefaultToBookmarksInSameTab #else
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc index e4fbbfc4..1964ef6 100644 --- a/chrome/browser/ui/browser_ui_prefs.cc +++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -8,6 +8,7 @@ #include "base/numerics/safe_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/upgrade_detector/upgrade_detector.h" @@ -21,7 +22,7 @@ #include "media/media_buildflags.h" #include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h" -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "ui/accessibility/accessibility_features.h" #endif @@ -82,7 +83,7 @@ registry->RegisterBooleanPref( prefs::kEnableDoNotTrack, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) registry->RegisterBooleanPref(prefs::kPrintPreviewUseSystemDefaultPrinter, false); #endif @@ -146,7 +147,7 @@ registry->RegisterBooleanPref(prefs::kShowCaretBrowsingDialog, true); #endif -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) registry->RegisterBooleanPref(prefs::kAccessibilityFocusHighlightEnabled, false); #endif
diff --git a/chrome/browser/ui/browser_unittest.cc b/chrome/browser/ui/browser_unittest.cc index 518d29f..e4dc414 100644 --- a/chrome/browser/ui/browser_unittest.cc +++ b/chrome/browser/ui/browser_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/browser.h" #include "base/macros.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" @@ -247,7 +248,7 @@ EXPECT_TRUE(otr_browser); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(BrowserUnitTest, CreateBrowserDuringKioskSplashScreen) { session_manager::SessionManager session_manager;
diff --git a/chrome/browser/ui/browser_view_prefs.cc b/chrome/browser/ui/browser_view_prefs.cc index 94773fc5..e2e59680 100644 --- a/chrome/browser/ui/browser_view_prefs.cc +++ b/chrome/browser/ui/browser_view_prefs.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/browser_view_prefs.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_registry_simple.h" @@ -26,7 +27,9 @@ // Old values: 0 = SHRINK (default), 1 = STACKED. const char kTabStripLayoutType[] = "tab_strip_layout_type"; -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) bool GetCustomFramePrefDefault() { #if defined(USE_OZONE) if (features::IsUsingOzonePlatform()) { @@ -51,10 +54,13 @@ void RegisterBrowserViewProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) registry->RegisterBooleanPref(prefs::kUseCustomChromeFrame, GetCustomFramePrefDefault()); -#endif // defined(OS_LINUX) && defined(!OS_CHROMEOS) +#endif // (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && + // defined(!OS_CHROMEOS) } void MigrateBrowserTabStripPrefs(PrefService* prefs) {
diff --git a/chrome/browser/ui/browser_window_state.cc b/chrome/browser/ui/browser_window_state.cc index 6a677ad..40c23a4 100644 --- a/chrome/browser/ui/browser_window_state.cc +++ b/chrome/browser/ui/browser_window_state.cc
@@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/defaults.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_service.h" @@ -78,7 +79,7 @@ std::string GetWindowName(const Browser* browser) { switch (browser->type()) { case Browser::TYPE_NORMAL: -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case Browser::TYPE_CUSTOM_TAB: #endif return prefs::kBrowserWindowPlacement;
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc index 75a43628..6561b096 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc
@@ -18,6 +18,7 @@ #include "base/strings/stringprintf.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -59,7 +60,7 @@ #include "ui/base/window_open_disposition.h" #include "url/url_util.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "base/metrics/histogram_functions.h" #include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_uma.h" @@ -106,7 +107,7 @@ ShowSingletonTabIgnorePathOverwriteNTP(browser, url); } -#if defined(OS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(GOOGLE_CHROME_BRANDING) void LaunchReleaseNotesImpl(Profile* profile, apps::mojom::LaunchSource source) { @@ -126,7 +127,7 @@ // is created. void ShowHelpImpl(Browser* browser, Profile* profile, HelpSource source) { base::RecordAction(UserMetricsAction("ShowHelpTab")); -#if defined(OS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(GOOGLE_CHROME_BRANDING) auto app_launch_source = apps::mojom::LaunchSource::kUnknown; switch (source) { case HELP_SOURCE_KEYBOARD: @@ -155,7 +156,7 @@ case HELP_SOURCE_MENU: url = GURL(kChromeHelpViaMenuURL); break; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case HELP_SOURCE_WEBUI: url = GURL(kChromeHelpViaWebUIURL); break; @@ -280,7 +281,7 @@ } void LaunchReleaseNotes(Profile* profile, apps::mojom::LaunchSource source) { -#if defined(OS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING) +#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(GOOGLE_CHROME_BRANDING) LaunchReleaseNotesImpl(profile, source); #endif } @@ -294,7 +295,7 @@ } void ShowSlow(Browser* browser) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ShowSingletonTab(browser, GURL(kChromeUISlowURL)); #endif } @@ -322,7 +323,7 @@ } void ShowSettingsSubPage(Browser* browser, const std::string& sub_page) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ShowSettingsSubPageForProfile(browser->profile(), sub_page); #else ShowSettingsSubPageInTabbedBrowser(browser, sub_page); @@ -331,7 +332,7 @@ void ShowSettingsSubPageForProfile(Profile* profile, const std::string& sub_page) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // OS settings sub-pages are handled else where and should never be // encountered here. DCHECK(!chromeos::settings::IsOSSettingsSubPage(sub_page)) << sub_page; @@ -419,7 +420,7 @@ ShowSettingsSubPage(browser, kSearchEnginesSubPage); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) void ShowEnterpriseManagementPageInTabbedBrowser(Browser* browser) { // Management shows in a tab because it has a "back" arrow that takes the // user to the Chrome browser about page, which is part of browser settings. @@ -478,7 +479,7 @@ } #endif -#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) +#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) void ShowBrowserSignin(Browser* browser, signin_metrics::AccessPoint access_point, signin::ConsentLevel consent_level) {
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h index 9b04495..ea710d9c 100644 --- a/chrome/browser/ui/chrome_pages.h +++ b/chrome/browser/ui/chrome_pages.h
@@ -10,6 +10,7 @@ #include <string> #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "url/gurl.h" @@ -18,7 +19,7 @@ #include "chrome/browser/signin/signin_promo.h" #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/printing/print_management/print_management_uma.h" #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_uma.h" #endif @@ -43,7 +44,7 @@ // WebUI (the "About" page). HELP_SOURCE_WEBUI, -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // WebUI (the OS "About" page). HELP_SOURCE_WEBUI_CHROME_OS, #endif @@ -144,7 +145,7 @@ void ShowAboutChrome(Browser* browser); void ShowSearchEngineSettings(Browser* browser); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Shows the enterprise management info page in a browser tab. void ShowEnterpriseManagementPageInTabbedBrowser(Browser* browser); @@ -163,7 +164,7 @@ void ShowScanningApp(Profile* profile); #endif -#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) +#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) // Initiates signin in a new browser tab. void ShowBrowserSignin(Browser* browser, signin_metrics::AccessPoint access_point,
diff --git a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc index 05ca8e5..217ee1a 100644 --- a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc +++ b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
@@ -13,6 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" @@ -41,7 +42,7 @@ #include "ui/events/event.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/web_applications/system_web_app_manager.h" #include "chrome/browser/web_applications/web_app_provider.h" #endif @@ -223,7 +224,7 @@ #define MAYBE_ManageButtonClicked ManageButtonClicked #endif IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest, MAYBE_ManageButtonClicked) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) web_app::WebAppProvider::Get(browser()->profile()) ->system_web_app_manager() .InstallSystemAppsForTesting();
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_browsertest.cc index 4989ed2..057f619 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_browsertest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/test/test_mock_time_task_runner.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -428,7 +429,7 @@ // Test Normal state <--> Browser fullscreen mode <--> Tab fullscreen mode. ToggleBrowserFullscreen(); EXPECT_TRUE(context->IsFullscreen()); -#if defined(OS_MAC) || defined(OS_CHROMEOS) +#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) bool should_show_top_ui = true; #else bool should_show_top_ui = false; @@ -437,7 +438,7 @@ EnterActiveTabFullscreen(); EXPECT_TRUE(context->IsFullscreen()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_TRUE(browser()->window()->IsToolbarVisible()); #else EXPECT_FALSE(browser()->window()->IsToolbarVisible());
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc index 5bb0a4d..612bbdd 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -30,10 +31,10 @@ #include "ui/display/screen_base.h" #include "ui/display/test/test_screen.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/shell.h" #include "ui/display/test/display_manager_test_api.h" -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) using url::kAboutBlankURL; using content::WebContents; @@ -465,7 +466,7 @@ ASSERT_TRUE(IsMouseLocked()); } -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) +#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_AURA) // These are flaky on linux_aura. // http://crbug.com/163931 #define MAYBE_TestTabExitsMouseLockOnNavigation \ @@ -518,7 +519,8 @@ ASSERT_FALSE(IsMouseLocked()); } -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA) || \ +#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \ + defined(USE_AURA) || \ defined(OS_WIN) && defined(NDEBUG) // TODO(erg): linux_aura bringup: http://crbug.com/163931 // Test is flaky on Windows: https://crbug.com/1124492 @@ -641,7 +643,7 @@ // where the window server's async handling of the fullscreen window state may // transition the window into fullscreen on the actual (non-mocked) display // bounds before or after the window bounds checks, yielding flaky results. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_FullscreenOnSecondDisplay DISABLED_FullscreenOnSecondDisplay #else #define MAYBE_FullscreenOnSecondDisplay FullscreenOnSecondDisplay @@ -651,7 +653,7 @@ IN_PROC_BROWSER_TEST_F(ExperimentalFullscreenControllerInteractiveTest, MAYBE_FullscreenOnSecondDisplay) { // Updates the display configuration to add a secondary display. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager()) .UpdateDisplay("100+100-801x802,901+100-801x802"); #else @@ -662,7 +664,7 @@ screen.display_list().AddDisplay({2, gfx::Rect(901, 100, 801, 802)}, display::DisplayList::Type::NOT_PRIMARY); display::Screen::SetScreenInstance(&screen); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ASSERT_EQ(2, display::Screen::GetScreen()->GetNumDisplays()); // Move the window to the first display (on the left). @@ -694,11 +696,11 @@ EXPECT_EQ(true, EvalJs(tab, request_fullscreen_script)); enter_fullscreen_observer.Wait(); EXPECT_TRUE(browser()->window()->IsFullscreen()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_EQ(gfx::Rect(801, 0, 801, 802), browser()->window()->GetBounds()); #else EXPECT_EQ(gfx::Rect(901, 100, 801, 802), browser()->window()->GetBounds()); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // Execute JS to exit fullscreen. FullscreenNotificationObserver exit_fullscreen_observer(browser()); @@ -713,7 +715,7 @@ EXPECT_FALSE(browser()->window()->IsFullscreen()); EXPECT_EQ(original_bounds, browser()->window()->GetBounds()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) display::Screen::SetScreenInstance(original_screen); #endif // !OS_CHROMEOS } @@ -725,7 +727,7 @@ // transition the window into fullscreen on the actual (non-mocked) display // bounds before or after the window bounds checks, yielding flaky results. // TODO(msw): Parameterize the maximized state and combine with the test above. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_FullscreenOnSecondDisplayMaximized \ DISABLED_FullscreenOnSecondDisplayMaximized #else @@ -738,7 +740,7 @@ IN_PROC_BROWSER_TEST_F(ExperimentalFullscreenControllerInteractiveTest, MAYBE_FullscreenOnSecondDisplayMaximized) { // Updates the display configuration to add a secondary display. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager()) .UpdateDisplay("100+100-801x802,901+100-801x802"); #else @@ -749,7 +751,7 @@ screen.display_list().AddDisplay({2, gfx::Rect(901, 100, 801, 802)}, display::DisplayList::Type::NOT_PRIMARY); display::Screen::SetScreenInstance(&screen); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ASSERT_EQ(2, display::Screen::GetScreen()->GetNumDisplays()); // Move the window to the first display (on the left) and maximize it. @@ -783,11 +785,11 @@ EXPECT_EQ(true, EvalJs(tab, request_fullscreen_script)); enter_fullscreen_observer.Wait(); EXPECT_TRUE(browser()->window()->IsFullscreen()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_EQ(gfx::Rect(801, 0, 801, 802), browser()->window()->GetBounds()); #else EXPECT_EQ(gfx::Rect(901, 100, 801, 802), browser()->window()->GetBounds()); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // Execute JS to exit fullscreen. FullscreenNotificationObserver exit_fullscreen_observer(browser()); @@ -803,7 +805,7 @@ EXPECT_EQ(maximized_bounds, browser()->window()->GetBounds()); EXPECT_TRUE(browser()->window()->IsMaximized()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) display::Screen::SetScreenInstance(original_screen); #endif // !OS_CHROMEOS } @@ -818,14 +820,14 @@ #endif IN_PROC_BROWSER_TEST_F(ExperimentalFullscreenControllerInteractiveTest, MAYBE_FullscreenOnScreensChange) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Install a mock screen object to be monitored by a new web contents. display::Screen* original_screen = display::Screen::GetScreen(); display::ScreenBase screen; screen.display_list().AddDisplay({1, gfx::Rect(100, 100, 801, 802)}, display::DisplayList::Type::PRIMARY); display::Screen::SetScreenInstance(&screen); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // Open a new foreground tab that will observe the mock screen object. ASSERT_TRUE(embedded_test_server()->Start()); @@ -852,18 +854,18 @@ FullscreenNotificationObserver fullscreen_observer(browser()); // Update the display configuration to trigger window.onscreenschange. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager()) .UpdateDisplay("100+100-801x802,901+100-801x802"); #else screen.display_list().AddDisplay({2, gfx::Rect(901, 100, 801, 802)}, display::DisplayList::Type::NOT_PRIMARY); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) fullscreen_observer.Wait(); EXPECT_TRUE(browser()->window()->IsFullscreen()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) display::Screen::SetScreenInstance(original_screen); #endif // !OS_CHROMEOS }
diff --git a/chrome/browser/ui/extensions/app_launch_params.cc b/chrome/browser/ui/extensions/app_launch_params.cc index ee3bfb5..2e708fa 100644 --- a/chrome/browser/ui/extensions/app_launch_params.cc +++ b/chrome/browser/ui/extensions/app_launch_params.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/extensions/app_launch_params.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/launch_utils.h" #include "chrome/browser/extensions/launch_util.h" #include "chrome/browser/profiles/profile.h" @@ -11,7 +12,7 @@ #include "extensions/common/constants.h" #include "extensions/common/extension.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/arc/arc_util.h" #include "components/arc/arc_util.h" #endif
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc index b827295..e6bd675 100644 --- a/chrome/browser/ui/extensions/application_launch.cc +++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -16,6 +16,7 @@ #include "base/metrics/histogram_macros.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/launch_utils.h" @@ -192,7 +193,7 @@ if (chrome::IsRunningInForcedAppMode()) return ui::SHOW_STATE_FULLSCREEN; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // In ash, LAUNCH_TYPE_FULLSCREEN launches in a maximized app window and // LAUNCH_TYPE_WINDOW launches in a default app window. extensions::LaunchType launch_type = @@ -281,7 +282,7 @@ tab_helper->SetAppId(extension->id()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // In ash, LAUNCH_FULLSCREEN launches in the OpenApplicationWindow function // i.e. it should not reach here. DCHECK(launch_type != extensions::LAUNCH_TYPE_FULLSCREEN); @@ -294,7 +295,7 @@ !browser->window()->IsFullscreen()) { chrome::ToggleFullscreenMode(browser); } -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) return contents; }
diff --git a/chrome/browser/ui/extensions/application_launch_browsertest.cc b/chrome/browser/ui/extensions/application_launch_browsertest.cc index 5705825..4d17902 100644 --- a/chrome/browser/ui/extensions/application_launch_browsertest.cc +++ b/chrome/browser/ui/extensions/application_launch_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -14,7 +15,7 @@ #include "content/public/test/browser_test_utils.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/shell.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/extensions/application_launch.h" @@ -24,7 +25,7 @@ #include "ui/display/screen.h" #include "ui/display/test/display_manager_test_api.h" #include "ui/gfx/native_widget_types.h" -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) class ApplicationLaunchBrowserTest : public InProcessBrowserTest { public: @@ -83,7 +84,7 @@ EXPECT_TRUE(app_browser->is_focus_mode()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(ApplicationLaunchBrowserTest, CreateWindowInDisplay) { display::Screen* screen = display::Screen::GetScreen(); // Create 2 displays. @@ -110,4 +111,4 @@ gfx::NativeWindow window2 = browser2->window()->GetNativeWindow(); EXPECT_EQ(display2, screen->GetDisplayNearestWindow(window2).id()); } -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc index 7c1ea16..e18e0f1 100644 --- a/chrome/browser/ui/extensions/extension_enable_flow.cc +++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/bind.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_util.h" @@ -18,9 +19,9 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/user_manager.h" -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" @@ -131,10 +132,10 @@ } if (profiles::IsProfileLocked(profile_->GetPath())) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) return; }
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc index 6b740f0..71626e35 100644 --- a/chrome/browser/ui/extensions/extension_install_ui_default.cc +++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" @@ -30,7 +31,7 @@ #include "extensions/browser/install/crx_install_error.h" #include "extensions/common/extension.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/extensions/extension_installed_notification.h" #else #include "chrome/common/url_constants.h" @@ -89,11 +90,11 @@ return; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ExtensionInstalledNotification::Show(extension.get(), current_profile); -#else // defined(OS_CHROMEOS) +#else // BUILDFLAG(IS_CHROMEOS_ASH) OpenAppInstalledUI(extension->id()); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) return; } @@ -118,7 +119,7 @@ } void ExtensionInstallUIDefault::OpenAppInstalledUI(const std::string& app_id) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Notification always enabled on ChromeOS, so always handled in // OnInstallSuccess. NOTREACHED();
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc index ec3184e..cb11a3d 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/extensions/extension_util.h" @@ -71,7 +72,7 @@ gfx::ImageSkia HostedAppBrowserController::GetWindowAppIcon() const { // TODO(calamity): Use the app name to retrieve the app icon without using the // extensions tab helper to make icon load more immediate. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) && apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile( browser()->profile())) {
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index 2e5fb06..6cad0b1 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -22,6 +22,7 @@ #include "base/test/scoped_feature_list.h" #include "base/values.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/apps/app_service/app_service_test.h" #include "chrome/browser/extensions/extension_browsertest.h" @@ -463,7 +464,7 @@ EXPECT_FALSE(app->from_bookmark()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_P(HostedAppTest, LoadIcon) { if (!base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) return;
diff --git a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc index bfe4304..f6ad4d8 100644 --- a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc +++ b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc
@@ -7,6 +7,7 @@ #include <utility> #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h" #include "chrome/browser/extensions/settings_api_bubble_delegate.h" #include "chrome/browser/extensions/settings_api_helpers.h" @@ -31,7 +32,7 @@ // Whether the NTP post-install UI is enabled. By default, this is limited to // Windows, Mac, and ChromeOS, but can be overridden for testing. -#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_CHROMEOS) +#if defined(OS_WIN) || defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) bool g_ntp_post_install_ui_enabled = true; #else bool g_ntp_post_install_ui_enabled = false;
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index 2238f85..b4ccbc2 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "build/buildflag.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -538,7 +539,7 @@ // Search Back and Forward on a single occurrence. // TODO(crbug.com/1119361): Test is flaky on ChromeOS. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define MAYBE_SingleOccurrence DISABLED_SingleOccurrence #else #define MAYBE_SingleOccurrence SingleOccurrence
diff --git a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc index 4af1d9e..78fb886 100644 --- a/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc +++ b/chrome/browser/ui/fullscreen_keyboard_browsertest_base.cc
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/strings/string_util.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -187,7 +188,7 @@ // On MACOSX, Command + Control + F is used. ASSERT_TRUE(ui_test_utils::SendKeyPressSync(GetActiveBrowser(), ui::VKEY_F, true, false, false, true)); -#elif defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_CHROMEOS_ASH) // A dedicated fullscreen key is used on Chrome OS, so send a fullscreen // command directly instead, to avoid constructing the key press. ASSERT_TRUE(chrome::ExecuteCommand(GetActiveBrowser(), IDC_FULLSCREEN));
diff --git a/chrome/browser/ui/global_error/global_error_browsertest.cc b/chrome/browser/ui/global_error/global_error_browsertest.cc index d144578..46c8fb2 100644 --- a/chrome/browser/ui/global_error/global_error_browsertest.cc +++ b/chrome/browser/ui/global_error/global_error_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_disabled_ui.h" @@ -41,7 +42,7 @@ #include "extensions/common/extension_builder.h" #include "extensions/common/feature_switch.h" -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/signin/signin_global_error.h" #include "chrome/browser/signin/signin_global_error_factory.h" #endif @@ -201,7 +202,7 @@ prefs::kRecoveryComponentNeedsElevation, true); waiter.Wait(); ShowPendingError(browser()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) } else if (name == "SigninGlobalError") { SigninGlobalErrorFactory::GetForProfile(profile)->ShowBubbleView(browser()); #endif @@ -246,7 +247,7 @@ #endif // Signin global errors never happon on ChromeOS. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(GlobalErrorBubbleTest, InvokeUi_SigninGlobalError) { ShowAndVerifyUi(); }
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service_factory.cc b/chrome/browser/ui/global_media_controls/media_notification_service_factory.cc index 6b287ea..31dd097 100644 --- a/chrome/browser/ui/global_media_controls/media_notification_service_factory.cc +++ b/chrome/browser/ui/global_media_controls/media_notification_service_factory.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/memory/singleton.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/global_media_controls/media_notification_service.h" @@ -35,7 +36,7 @@ KeyedService* MediaNotificationServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { bool show_from_all_profiles = false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) show_from_all_profiles = true; #endif return new MediaNotificationService(Profile::FromBrowserContext(context),
diff --git a/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc b/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc index 3608b25b..decba42 100644 --- a/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc +++ b/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/macros.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/fullscreen_keyboard_browsertest_base.h" #include "chrome/test/base/in_process_browser_test.h" @@ -261,7 +262,7 @@ // https://crbug.com/1108391 Flakey on ChromeOS. // https://crbug.com/1121172 Also flaky on Lacros. -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #define MAYBE_SubsequentLockCallSupersedesPreviousCall \ DISABLED_SubsequentLockCallSupersedesPreviousCall #else
diff --git a/chrome/browser/ui/managed_ui.cc b/chrome/browser/ui/managed_ui.cc index bdbb289d..60931ee 100644 --- a/chrome/browser/ui/managed_ui.cc +++ b/chrome/browser/ui/managed_ui.cc
@@ -5,13 +5,14 @@ #include "chrome/browser/ui/managed_ui.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/enterprise/util/managed_browser_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/management_ui_handler.h" #include "chrome/grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" @@ -22,7 +23,7 @@ namespace chrome { bool ShouldDisplayManagedUi(Profile* profile) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Don't show the UI in demo mode. if (chromeos::DemoSession::IsDeviceInDemoMode()) return false; @@ -63,7 +64,7 @@ return l10n_util::GetStringFUTF16(string_id, replacements, nullptr); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) base::string16 GetDeviceManagedUiWebUILabel() { policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos();
diff --git a/chrome/browser/ui/managed_ui.h b/chrome/browser/ui/managed_ui.h index f4a85cbd..21cd65d 100644 --- a/chrome/browser/ui/managed_ui.h +++ b/chrome/browser/ui/managed_ui.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_MANAGED_UI_H_ #include "base/strings/string16.h" +#include "build/chromeos_buildflags.h" class Profile; @@ -30,7 +31,7 @@ // is managed. These strings contain HTML for an <a> element. base::string16 GetManagedUiWebUILabel(Profile* profile); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // The label for the WebUI footnote for Managed UI indicating that the device // is mananged. These strings contain HTML for an <a> element. base::string16 GetDeviceManagedUiWebUILabel();
diff --git a/chrome/browser/ui/managed_ui_browsertest.cc b/chrome/browser/ui/managed_ui_browsertest.cc index 44a9fc56e..640745b 100644 --- a/chrome/browser/ui/managed_ui_browsertest.cc +++ b/chrome/browser/ui/managed_ui_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/test/base/in_process_browser_test.h" @@ -15,7 +16,7 @@ #include "content/public/test/browser_test.h" #include "testing/gmock/include/gmock/gmock.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #endif @@ -51,7 +52,7 @@ base::Value("hello world"), nullptr); provider()->UpdateChromePolicy(policy_map); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_FALSE(chrome::ShouldDisplayManagedUi(browser()->profile())); #else EXPECT_TRUE(chrome::ShouldDisplayManagedUi(browser()->profile())); @@ -94,7 +95,7 @@ chrome::GetManagedUiWebUILabel(profile_with_domain.get())); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) using ManagedUiTestCros = policy::DevicePolicyCrosBrowserTest; IN_PROC_BROWSER_TEST_F(ManagedUiTestCros, GetManagedUiWebUILabel) { EXPECT_EQ(base::ASCIIToUTF16("Your <a target=\"_blank\" "
diff --git a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc index aa4f66c4..e176bd1 100644 --- a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc +++ b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
@@ -4,6 +4,7 @@ #include "base/environment.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "components/omnibox/browser/autocomplete_input.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/omnibox_pedal_provider.h" @@ -561,7 +562,7 @@ OmniboxPedalProvider provider(client); EXPECT_EQ(provider.FindPedalMatch(input, base::UTF8ToUTF16("")), nullptr); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // TODO(orinj): Get ChromeOS to use the right dataset, but for now make this // a soft failure so as to not block all other platforms. To ensure this // is not going to cause failure in production, still test that English
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc index 7ba657d..e1142f3 100644 --- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc +++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -17,6 +17,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/history/history_service_factory.h" @@ -432,7 +433,7 @@ ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_X, kCtrlOrCmdMask)); EXPECT_EQ(ASCIIToUTF16("Hello "), omnibox_view->GetText()); -#if !defined(OS_CHROMEOS) && !defined(OS_MAC) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_MAC) // Try alt-f4 to close the browser. ExpectBrowserClosed(browser(), ui::VKEY_F4, ui::EF_ALT_DOWN); #endif @@ -472,7 +473,7 @@ EXPECT_EQ(ASCIIToUTF16("Hello world"), omnibox_view->GetText()); EXPECT_TRUE(omnibox_view->IsSelectAll()); -#if !defined(OS_CHROMEOS) && !defined(OS_MAC) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_MAC) // Try alt-f4 to close the popup. ExpectBrowserClosed(popup, ui::VKEY_F4, ui::EF_ALT_DOWN); #endif
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc index f48de8b..6e8af4b1 100644 --- a/chrome/browser/ui/page_info/page_info_unittest.cc +++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/content_settings/page_specific_content_settings_delegate.h" #include "chrome/browser/infobars/mock_infobar_service.h" @@ -897,7 +898,7 @@ page_info()->site_identity_status()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(PageInfoTest, HTTPSPolicyCertConnection) { security_level_ = security_state::SECURE_WITH_POLICY_INSTALLED_CERT; visible_security_state_.url = GURL("https://scheme-is-cryptographic.test");
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc index d8ae8d0..54daf8d 100644 --- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc +++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h" #include "chrome/test/base/testing_profile.h" @@ -393,14 +394,14 @@ pending_password().password_value)); controller()->OnSaveClicked(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_FALSE(controller()->ReplaceToShowPromotionIfNeeded()); #else EXPECT_TRUE(controller()->ReplaceToShowPromotionIfNeeded()); #endif } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(SaveUpdateBubbleControllerTest, SignInPromoCancel) { base::HistogramTester histogram_tester; PretendPasswordWaiting(); @@ -432,7 +433,7 @@ EXPECT_FALSE(prefs()->GetBoolean( password_manager::prefs::kWasSignInPasswordPromoClicked)); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) // Verify that URL keyed metrics are properly recorded. TEST_F(SaveUpdateBubbleControllerTest, RecordUKMs) {
diff --git a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc index bf7fb019..d4af1694 100644 --- a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc +++ b/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h" #include "chrome/test/base/testing_profile.h" #include "components/password_manager/core/browser/password_form.h" @@ -66,7 +67,7 @@ new SignInPromoBubbleController(mock_delegate_->AsWeakPtr())); } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) TEST_F(SignInPromoBubbleControllerTest, SignInPromoOK) { Init(); AccountInfo account;
diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc index 0b4aece..919746a 100644 --- a/chrome/browser/ui/prefs/pref_watcher.cc +++ b/chrome/browser/ui/prefs/pref_watcher.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" @@ -16,7 +17,7 @@ #include "components/language/core/browser/pref_names.h" #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/ash_pref_names.h" #endif @@ -55,7 +56,7 @@ prefs::kWebkitTabsToLinks, prefs::kWebKitTextAreasAreResizable, prefs::kWebKitWebSecurityEnabled, -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) ash::prefs::kAccessibilityFocusHighlightEnabled, #else prefs::kAccessibilityFocusHighlightEnabled,
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc index 1d2032c..45f928b 100644 --- a/chrome/browser/ui/prefs/prefs_tab_helper.cc +++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -19,6 +19,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/font_pref_change_notifier_factory.h" @@ -135,7 +136,7 @@ {prefs::kWebKitCursiveFontFamily, IDS_CURSIVE_FONT_FAMILY}, {prefs::kWebKitFantasyFontFamily, IDS_FANTASY_FONT_FAMILY}, {prefs::kWebKitPictographFontFamily, IDS_PICTOGRAPH_FONT_FAMILY}, -#if defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_WIN) +#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) || defined(OS_WIN) {prefs::kWebKitStandardFontFamilyJapanese, IDS_STANDARD_FONT_FAMILY_JAPANESE}, {prefs::kWebKitFixedFontFamilyJapanese, IDS_FIXED_FONT_FAMILY_JAPANESE}, @@ -165,7 +166,7 @@ {prefs::kWebKitCursiveFontFamilyTraditionalHan, IDS_CURSIVE_FONT_FAMILY_TRADITIONAL_HAN}, #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) {prefs::kWebKitStandardFontFamilyArabic, IDS_STANDARD_FONT_FAMILY_ARABIC}, {prefs::kWebKitSerifFontFamilyArabic, IDS_SERIF_FONT_FAMILY_ARABIC}, {prefs::kWebKitSansSerifFontFamilyArabic,
diff --git a/chrome/browser/ui/profile_error_browsertest.cc b/chrome/browser/ui/profile_error_browsertest.cc index 86905b0f..44f3b59 100644 --- a/chrome/browser/ui/profile_error_browsertest.cc +++ b/chrome/browser/ui/profile_error_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/simple_message_box_internal.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -71,7 +72,7 @@ const bool do_corrupt_; }; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Disable the test on chromos since kernel controls the user profile thus we // won't be able to corrupt it. #define MAYBE_CorruptedProfile DISABLED_CorruptedProfile
diff --git a/chrome/browser/ui/renderer_event_injection_browsertest.cc b/chrome/browser/ui/renderer_event_injection_browsertest.cc index c41ccd8..fb82d886 100644 --- a/chrome/browser/ui/renderer_event_injection_browsertest.cc +++ b/chrome/browser/ui/renderer_event_injection_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" +#include "build/chromeos_buildflags.h" #include "cc/base/switches.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -52,7 +53,7 @@ command_line->AppendSwitch(switches::kDisableRendererBackgrounding); command_line->AppendSwitch(cc::switches::kEnableGpuBenchmarking); // kHostWindowBounds is unique to ChromeOS. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) command_line->AppendSwitchASCII(switches::kHostWindowBounds, GetParam()); #endif embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); @@ -123,7 +124,7 @@ rwh->RemoveInputEventObserver(&touch_observer); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // This configures the display in various interesting ways for ChromeOS. In // particular, it tests rotation "/r" and a scale factor of 2 "*2". INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ui/sad_tab.cc b/chrome/browser/ui/sad_tab.cc index d8dc3b0e..a5c6d700 100644 --- a/chrome/browser/ui/sad_tab.cc +++ b/chrome/browser/ui/sad_tab.cc
@@ -26,7 +26,7 @@ #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/browser/memory/oom_memory_details.h" #endif @@ -91,7 +91,7 @@ switch (status) { case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM: #endif case base::TERMINATION_STATUS_PROCESS_CRASHED: @@ -117,7 +117,7 @@ if (!is_repeatedly_crashing_) return IDS_SAD_TAB_TITLE; switch (kind_) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case SAD_TAB_KIND_KILLED_BY_OOM: return IDS_SAD_TAB_RELOAD_TITLE; #endif @@ -139,7 +139,7 @@ int SadTab::GetInfoMessage() { switch (kind_) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case SAD_TAB_KIND_KILLED_BY_OOM: return IDS_KILLED_TAB_BY_OOM_MESSAGE; #endif @@ -176,7 +176,7 @@ return std::vector<int>(); switch (kind_) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case SAD_TAB_KIND_KILLED_BY_OOM: return std::vector<int>(); #endif @@ -218,7 +218,7 @@ case SAD_TAB_KIND_OOM: UMA_SAD_TAB_COUNTER("Tabs.SadTab.OomDisplayed"); break; -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case SAD_TAB_KIND_KILLED_BY_OOM: UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillDisplayed.OOM"); FALLTHROUGH; @@ -280,7 +280,7 @@ case SAD_TAB_KIND_OOM: UMA_SAD_TAB_COUNTER("Tabs.SadTab.OomCreated"); break; -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case SAD_TAB_KIND_KILLED_BY_OOM: UMA_SAD_TAB_COUNTER("Tabs.SadTab.KillCreated.OOM"); {
diff --git a/chrome/browser/ui/sad_tab_helper.cc b/chrome/browser/ui/sad_tab_helper.cc index 589e3a5..3f264455 100644 --- a/chrome/browser/ui/sad_tab_helper.cc +++ b/chrome/browser/ui/sad_tab_helper.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/sad_tab_helper.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/ui/sad_tab.h" #include "content/public/browser/navigation_handle.h" @@ -15,7 +16,7 @@ SadTabKind SadTabKindFromTerminationStatus(base::TerminationStatus status) { switch (status) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM: return SAD_TAB_KIND_KILLED_BY_OOM; #endif
diff --git a/chrome/browser/ui/sad_tab_types.h b/chrome/browser/ui/sad_tab_types.h index 4a688c44..106f779 100644 --- a/chrome/browser/ui/sad_tab_types.h +++ b/chrome/browser/ui/sad_tab_types.h
@@ -10,7 +10,7 @@ enum SadTabKind { SAD_TAB_KIND_CRASHED, // Tab crashed. -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) SAD_TAB_KIND_KILLED_BY_OOM, // Tab killed by oom killer. #endif SAD_TAB_KIND_OOM, // Tab ran out of memory.
diff --git a/chrome/browser/ui/startup/bad_flags_prompt.cc b/chrome/browser/ui/startup/bad_flags_prompt.cc index 3b3bb4b..2d18213 100644 --- a/chrome/browser/ui/startup/bad_flags_prompt.cc +++ b/chrome/browser/ui/startup/bad_flags_prompt.cc
@@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/ui/simple_message_box.h" #include "chrome/common/chrome_paths.h" @@ -88,7 +89,9 @@ extensions::switches::kExtensionsOnChromeURLs, #endif -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) // Speech dispatcher is buggy, it can crash and it can make Chrome freeze. // http://crbug.com/327295 switches::kEnableSpeechDispatcher,
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc index 6516a76..9dead78c 100644 --- a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc +++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
@@ -12,10 +12,10 @@ #include "base/strings/string_split.h" #include "base/syslog_logging.h" #include "chrome/credential_provider/common/gcp_strings.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_oauth_client.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/oauth2_access_token_fetcher.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "google_apis/google_api_keys.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -23,9 +23,11 @@ const std::string& refresh_token, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : scoped_access_token_fetcher_( - std::make_unique<OAuth2AccessTokenFetcherImpl>(this, - url_loader_factory, - refresh_token)), + GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + this, + url_loader_factory, + refresh_token)), user_info_fetcher_( std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)), token_handle_fetcher_(
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 27f6fb8..4d7c99a 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -31,6 +31,7 @@ #include "base/trace_event/trace_event.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -79,7 +80,7 @@ #include "extensions/common/switches.h" #include "printing/buildflags/buildflags.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/app_mode/app_launch_utils.h" #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -253,7 +254,7 @@ // Returns whether |profile| can be opened during Chrome startup without // explicit user action. bool CanOpenProfileOnStartup(Profile* profile) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // On ChromeOS, the user has already chosen and logged into the profile before // Chrome starts up. return true; @@ -278,10 +279,10 @@ } void ShowUserManagerOnStartup() { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) } bool IsSilentLaunchEnabled(const base::CommandLine& command_line, @@ -294,10 +295,10 @@ if (command_line.HasSwitch(switches::kSilentLaunch)) return true; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return profile->GetPrefs()->GetBoolean( prefs::kStartupBrowserWindowLaunchSuppressed); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) return false; } @@ -514,7 +515,7 @@ // is starting Chrome for the first time. On Chrome OS, the sentinel is stored // in a location shared by all users and the check is meaningless. Query the // UserManager instead to determine whether the user is new. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) const bool is_first_run = user_manager::UserManager::Get()->IsCurrentUserNew(); // On ChromeOS restarts force the user to login again. The expectation is that @@ -577,7 +578,7 @@ // static void StartupBrowserCreator::RegisterLocalStatePrefs( PrefRegistrySimple* registry) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) registry->RegisterBooleanPref(prefs::kPromotionalTabsEnabled, true); registry->RegisterBooleanPref(prefs::kCommandLineFlagSecurityWarningsEnabled, true); @@ -650,7 +651,7 @@ const GURL settings_url = GURL(chrome::kChromeUISettingsURL); bool url_points_to_an_approved_settings_page = false; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // In ChromeOS, allow any settings page to be specified on the command line. url_points_to_an_approved_settings_page = url.GetOrigin() == settings_url.GetOrigin(); @@ -669,7 +670,7 @@ url_points_to_an_approved_settings_page || url == reset_settings_url_with_cct_hash; #endif // defined(OS_WIN) -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance(); @@ -733,7 +734,7 @@ return false; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // The browser will be launched after the user logs in. if (command_line.HasSwitch(chromeos::switches::kLoginManager)) @@ -773,7 +774,7 @@ chrome::AttemptUserExit(); return false; } -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(TOOLKIT_VIEWS) && defined(USE_X11) if (!features::IsUsingOzonePlatform()) { @@ -803,7 +804,7 @@ silent_launch = true; } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (base::FeatureList::IsEnabled(features::kOnConnectNative) && command_line.HasSwitch(switches::kNativeMessagingConnectHost) && command_line.HasSwitch(switches::kNativeMessagingConnectExtension)) { @@ -961,7 +962,7 @@ bool process_startup, Profile* last_used_profile, const Profiles& last_opened_profiles) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) const std::vector<GURL> urls_to_launch = StartupBrowserCreator::GetURLsFromCommandLine(command_line, cur_dir, last_used_profile); @@ -972,7 +973,7 @@ : ProfilePicker::EntryPoint::kNewSessionOnExistingProcess); return true; } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) chrome::startup::IsProcessStartup is_process_startup = process_startup ? chrome::startup::IS_PROCESS_STARTUP @@ -1034,7 +1035,7 @@ for (Profile* profile : last_opened_profiles) { DCHECK(!profile->IsGuestSession() && !profile->IsEphemeralGuestProfile()); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Skip any locked profile. if (!CanOpenProfileOnStartup(profile)) continue; @@ -1080,7 +1081,7 @@ // Note that this must be done after all profiles have // been launched so the observer knows about all profiles to wait before // activation this one. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (is_process_startup == chrome::startup::IS_PROCESS_STARTUP) ShowUserManagerOnStartup(); else @@ -1155,13 +1156,13 @@ } StartupBrowserCreator startup_browser_creator; Profiles last_opened_profiles; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // On ChromeOS multiple profiles doesn't apply. // If no browser windows are open, i.e. the browser is being kept alive in // background mode or for other processing, restore |last_opened_profiles|. if (chrome::GetTotalBrowserCount() == 0) last_opened_profiles = profile_manager->GetLastOpenedProfiles(); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) startup_browser_creator.ProcessCmdLineImpl(command_line, cur_dir, /*process_startup=*/false, profile, last_opened_profiles); @@ -1223,7 +1224,7 @@ user_data_dir); } -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) Profile* GetStartupProfile(const base::FilePath& user_data_dir, const base::CommandLine& command_line) { ProfileManager* profile_manager = g_browser_process->profile_manager(); @@ -1294,4 +1295,4 @@ return nullptr; } -#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index 36747ee..9fc735d 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/startup/startup_types.h" @@ -213,7 +214,7 @@ base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir, const base::CommandLine& command_line); -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) // Returns the profile that should be loaded on process startup. This is either // the profile returned by GetStartupProfilePath, or the guest profile if the // above profile is locked. The guest profile denotes that we should open the @@ -228,6 +229,6 @@ // guest profile means the caller should open the user manager. This may return // null if neither any profile nor the user manager can be opened. Profile* GetFallbackStartupProfile(); -#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) #endif // CHROME_BROWSER_UI_STARTUP_STARTUP_BROWSER_CREATOR_H_
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 7c6c1b2..3513ba2 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -21,6 +21,7 @@ #include "base/threading/thread_restrictions.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" @@ -90,7 +91,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) #include "base/callback.h" #include "base/run_loop.h" #include "base/values.h" @@ -100,7 +101,7 @@ #include "components/policy/core/common/policy_types.h" using testing::Return; -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_constants.h" @@ -122,7 +123,7 @@ namespace { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) const char kAppId[] = "dofnemchnjfeendjmdhaldenaiabpiad"; const char kAppName[] = "Test App"; @@ -169,7 +170,7 @@ return OpenNewBrowser(profile); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) typedef base::Optional<policy::PolicyLevel> PolicyVariant; @@ -253,7 +254,7 @@ void SetUpCommandLine(base::CommandLine* command_line) override { extensions::ExtensionBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII(switches::kHomePage, url::kAboutBlankURL); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // TODO(nkostylev): Investigate if we can remove this switch. command_line->AppendSwitch(switches::kCreateBrowserOnStartupForTests); #endif @@ -344,7 +345,7 @@ // We don't do non-process-startup browser launches on ChromeOS. // Session restore for process-startup browser launches is tested // in session_restore_uitest. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Verify that startup URLs are honored when the process already exists but has // no tabbed browser windows (eg. as if the process is running only due to a // background application. @@ -542,7 +543,7 @@ << browser()->app_name_; } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_WIN) IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, ValidNotificationLaunchId) { @@ -642,7 +643,7 @@ EXPECT_FALSE(StartupBrowserCreator::WasRestarted()); } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, StartupURLsForTwoProfiles) { Profile* default_profile = browser()->profile(); @@ -1367,7 +1368,7 @@ EXPECT_EQ("/title2.html", tab_strip->GetWebContentsAt(0)->GetURL().path()); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) class StartupBrowserCreatorExtensionsCheckupExperimentTest : public extensions::ExtensionBrowserTest { @@ -1471,7 +1472,7 @@ // These tests are not applicable to Chrome OS as neither initial preferences // nor the onboarding promos exist there. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) class StartupBrowserCreatorFirstRunTest : public InProcessBrowserTest { public: @@ -1754,7 +1755,7 @@ tab_strip->GetWebContentsAt(0)->GetURL().ExtractFileName()); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) class StartupBrowserCreatorWelcomeBackTest : public InProcessBrowserTest { protected: @@ -1870,7 +1871,7 @@ } // The kCommandLineFlagSecurityWarningsEnabled policy doesn't exist on ChromeOS. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) enum class CommandLineFlagSecurityWarningsPolicy { kNoPolicy, kEnabled, @@ -2208,4 +2209,4 @@ INSTANTIATE_TEST_SUITE_P(All, GuestStartupBrowserCreatorPickerTest, /*ephemeral_guest_profile_enabled=*/testing::Bool()); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index f1a9ede..61a6cb50 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -78,7 +78,7 @@ #include "components/rlz/rlz_tracker.h" // nogncheck #endif -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/grit/generated_resources.h" #include "components/infobars/core/simple_alert_infobar_delegate.h" #include "ui/base/l10n/l10n_util.h" @@ -112,7 +112,7 @@ } bool ShouldShowBadFlagsSecurityWarnings() { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) PrefService* local_state = g_browser_process->local_state(); if (!local_state) return true; @@ -315,11 +315,11 @@ // administrative policy. bool promotional_tabs_enabled = true; const PrefService::Preference* enabled_pref = nullptr; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) PrefService* local_state = g_browser_process->local_state(); if (local_state) enabled_pref = local_state->FindPreference(prefs::kPromotionalTabsEnabled); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) if (enabled_pref && enabled_pref->IsManaged()) { // Presentation is managed; obey the policy setting. promotional_tabs_enabled = enabled_pref->GetValue()->GetBool(); @@ -332,10 +332,10 @@ } bool welcome_enabled = true; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) welcome_enabled = welcome::IsEnabled(profile_) && welcome::HasModulesToShow(profile_); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) bool serve_extensions_page = extensions::ShouldShowExtensionsCheckupOnStartup(profile_); @@ -573,7 +573,7 @@ InfoBarService* infobar_service = InfoBarService::FromWebContents(web_contents); -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) // Show the experimental lacros info bar. auto_expire must be set to false, // since otherwise an automated navigation [which can happen at launch] will // cause the info bar to disappear. @@ -600,7 +600,7 @@ MacSystemInfoBarDelegate::Create(infobar_service); #endif -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (!command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) { // The default browser prompt should only be shown after the first run. if (!is_first_run_)
diff --git a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc index 9ca878f..986fb45a 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" @@ -36,7 +37,7 @@ // Chrome OS doesn't support multiprofile. // And BrowserWindow::IsActive() always returns false in tests on MAC. // And this test is useless without that functionality. -#if !defined(OS_CHROMEOS) && !defined(OS_MAC) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_MAC) IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, LastUsedProfileActivated) { base::ScopedAllowBlockingForTesting allow_blocking; ProfileManager* profile_manager = g_browser_process->profile_manager();
diff --git a/chrome/browser/ui/startup/startup_tab_provider.cc b/chrome/browser/ui/startup/startup_tab_provider.cc index ab549af..b16e6b9 100644 --- a/chrome/browser/ui/startup/startup_tab_provider.cc +++ b/chrome/browser/ui/startup/startup_tab_provider.cc
@@ -6,6 +6,7 @@ #include "base/metrics/histogram_macros.h" #include "build/branding_buildflags.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/profile_resetter/triggered_profile_resetter.h" #include "chrome/browser/profile_resetter/triggered_profile_resetter_factory.h" @@ -47,7 +48,7 @@ StartupTabs StartupTabProviderImpl::GetOnboardingTabs(Profile* profile) const { // Chrome OS has its own welcome flow provided by OOBE. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return StartupTabs(); #else if (!profile) @@ -67,7 +68,7 @@ standard_params.is_force_signin_enabled = signin_util::IsForceSigninEnabled(); return GetStandardOnboardingTabsForState(standard_params); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } StartupTabs StartupTabProviderImpl::GetWelcomeBackTabs(
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc index 9667f7e..0041eb457 100644 --- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc +++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" @@ -40,7 +41,7 @@ #endif IN_PROC_BROWSER_TEST_F(ProfileSigninConfirmationHelperBrowserTest, MAYBE_HasNotBeenShutdown) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_TRUE(first_run::auto_import_state() & first_run::AUTO_IMPORT_CALLED); #endif EXPECT_FALSE(ui::HasBeenShutdown(browser()->profile()));
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc index e810f46..1134ce4 100644 --- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc +++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -19,6 +19,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/prefs/browser_prefs.h" @@ -37,7 +38,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #endif @@ -179,7 +180,7 @@ TestingPrefStoreWithCustomReadError* user_prefs_; BookmarkModel* model_; -#if defined OS_CHROMEOS +#if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_; chromeos::ScopedTestUserManager test_user_manager_; #endif
diff --git a/chrome/browser/ui/sync/sync_promo_ui_unittest.cc b/chrome/browser/ui/sync/sync_promo_ui_unittest.cc index 6221d5e..d027d10f 100644 --- a/chrome/browser/ui/sync/sync_promo_ui_unittest.cc +++ b/chrome/browser/ui/sync/sync_promo_ui_unittest.cc
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/testing_profile.h" #include "components/sync/driver/sync_driver_switches.h" @@ -51,7 +52,7 @@ // Verifies that ShouldShowSyncPromo returns true if all conditions to // show the promo are met. TEST_F(SyncPromoUITest, ShouldShowSyncPromoSyncEnabled) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // No sync promo on CrOS. EXPECT_FALSE(SyncPromoUI::ShouldShowSyncPromo(profile_.get())); #else
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 4fb7af3b..78bf9b43 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -12,6 +12,7 @@ #include "base/time/default_tick_clock.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/buildflags.h" @@ -142,7 +143,7 @@ #include "components/zoom/zoom_controller.h" #endif // defined(OS_ANDROID) -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/child_accounts/time_limits/web_time_navigation_observer.h" #include "chrome/browser/chromeos/policy/dlp/dlp_content_tab_helper.h" #include "chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder_tab_tracker.h" @@ -398,15 +399,17 @@ web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) app_list::CrOSActionRecorderTabTracker::CreateForWebContents(web_contents); chromeos::app_time::WebTimeNavigationObserver::MaybeCreateForWebContents( web_contents); policy::DlpContentTabHelper::CreateForWebContents(web_contents); #endif +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. #if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !defined(OS_CHROMEOS)) + (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) metrics::DesktopSessionDurationObserver::CreateForWebContents(web_contents); #endif
diff --git a/chrome/browser/ui/tabs/tab_renderer_data.cc b/chrome/browser/ui/tabs/tab_renderer_data.cc index d70e049..01df75e 100644 --- a/chrome/browser/ui/tabs/tab_renderer_data.cc +++ b/chrome/browser/ui/tabs/tab_renderer_data.cc
@@ -72,7 +72,7 @@ bool TabRendererData::IsCrashed() const { return (crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED || -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM || #endif
diff --git a/chrome/browser/ui/task_manager/task_manager_columns.cc b/chrome/browser/ui/task_manager/task_manager_columns.cc index 2a97d6c..50bd9ed 100644 --- a/chrome/browser/ui/task_manager/task_manager_columns.cc +++ b/chrome/browser/ui/task_manager/task_manager_columns.cc
@@ -7,6 +7,7 @@ #include "base/notreached.h" #include "base/stl_util.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/grit/generated_resources.h" #include "components/nacl/common/buildflags.h" @@ -30,7 +31,7 @@ base::size("800 MiB") * kCharWidth, base::size("Memory Footprint") * 1.5 * kCharWidth, true, false, true}, -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) {IDS_TASK_MANAGER_SWAPPED_MEM_COLUMN, ui::TableColumn::RIGHT, -1, 0, base::size("800 MiB") * kCharWidth, -1, true, false, false}, #endif
diff --git a/chrome/browser/ui/test/test_browser_dialog.cc b/chrome/browser/ui/test/test_browser_dialog.cc index 1863e4e..d6efd49 100644 --- a/chrome/browser/ui/test/test_browser_dialog.cc +++ b/chrome/browser/ui/test/test_browser_dialog.cc
@@ -11,9 +11,10 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/shell.h" #endif @@ -114,7 +115,9 @@ views::Widget* dialog_widget = *(added.begin()); // TODO(https://crbug.com/958242) support Mac for pixel tests. -#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) dialog_widget->SetBlockCloseForTesting(true); // Deactivate before taking screenshot. Deactivated dialog pixel outputs // is more predictable than activated dialog. @@ -195,7 +198,7 @@ void TestBrowserDialog::UpdateWidgets() { widgets_.clear(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) for (aura::Window* root_window : ash::Shell::GetAllRootWindows()) views::Widget::GetAllChildWidgets(root_window, &widgets_); #elif defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/ui/test/test_browser_ui.cc b/chrome/browser/ui/test/test_browser_ui.cc index 6deede6..35ef2c5 100644 --- a/chrome/browser/ui/test/test_browser_ui.cc +++ b/chrome/browser/ui/test/test_browser_ui.cc
@@ -8,9 +8,12 @@ #include "base/test/gtest_util.h" #include "base/test/test_switches.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. #if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !defined(OS_CHROMEOS)) + (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) #include "chrome/test/pixel/browser_skia_gold_pixel_diff.h" #include "ui/base/test/skia_gold_matching_algorithm.h" #include "ui/compositor/test/draw_waiter_for_test.h" @@ -32,7 +35,9 @@ } // namespace TestBrowserUi::TestBrowserUi() { -#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) // Default to fuzzy diff. The magic number is chosen based on // past experiments. SetPixelMatchAlgorithm( @@ -43,7 +48,9 @@ TestBrowserUi::~TestBrowserUi() = default; // TODO(https://crbug.com/958242) support Mac for pixel tests. -#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) bool TestBrowserUi::VerifyPixelUi(views::Widget* widget, const std::string& screenshot_prefix, const std::string& screenshot_name) {
diff --git a/chrome/browser/ui/test/test_browser_ui.h b/chrome/browser/ui/test/test_browser_ui.h index 8658d5c..6d9ce3f 100644 --- a/chrome/browser/ui/test/test_browser_ui.h +++ b/chrome/browser/ui/test/test_browser_ui.h
@@ -9,6 +9,7 @@ #include <string> #include "base/macros.h" +#include "build/chromeos_buildflags.h" #include "chrome/test/base/in_process_browser_test.h" namespace views { @@ -91,7 +92,9 @@ // successfully shown. virtual bool VerifyUi() = 0; -#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) // Can be called by VerifyUi() to ensure pixel correctness. bool VerifyPixelUi(views::Widget* widget, const std::string& screenshot_prefix, @@ -120,8 +123,10 @@ void ShowAndVerifyUi(); private: +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. #if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !defined(OS_CHROMEOS)) + (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) std::unique_ptr<ui::test::SkiaGoldMatchingAlgorithm> algorithm_; #endif
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc index 3b462a9..4aa93919 100644 --- a/chrome/browser/ui/toolbar/app_menu_model.cc +++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -19,6 +19,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/branding_buildflags.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/banners/app_banner_manager.h" @@ -83,11 +84,11 @@ #include "ui/gfx/text_elider.h" #include "ui/native_theme/native_theme.h" -#if BUILDFLAG(GOOGLE_CHROME_BRANDING) || defined(OS_CHROMEOS) +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) || BUILDFLAG(IS_CHROMEOS_ASH) #include "base/feature_list.h" #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/tablet_mode.h" #include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h" #include "chromeos/constants/chromeos_features.h" @@ -178,12 +179,12 @@ private: void Build(Browser* browser) { -#if defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD) +#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(OFFICIAL_BUILD) int help_string_id = IDS_GET_HELP; #else int help_string_id = IDS_HELP_PAGE; #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); #else AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); @@ -226,7 +227,7 @@ AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS); if (chrome::CanOpenTaskManager()) AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) AddItemWithStringId(IDC_TAKE_SCREENSHOT, IDS_TAKE_SCREENSHOT); #endif AddSeparator(ui::NORMAL_SEPARATOR); @@ -274,7 +275,7 @@ Observe(tab_strip_model->GetActiveWebContents()); UpdateZoomControls(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) PrefService* const local_state = g_browser_process->local_state(); if (local_state) { local_state_pref_change_registrar_.Init(local_state); @@ -284,7 +285,7 @@ base::Unretained(this))); UpdateSettingsItemState(); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } bool AppMenuModel::DoesCommandIdDismissMenu(int command_id) const { @@ -834,7 +835,7 @@ } } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Always show this option if we're in tablet mode on Chrome OS. if (base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kEnableRequestTabletSite) || @@ -859,7 +860,7 @@ sub_menus_.push_back(std::make_unique<HelpMenuModel>(this, browser_)); AddSubMenuWithStringId(IDC_HELP_MENU, IDS_HELP_MENU, sub_menus_.back().get()); #else -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); #else AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT)); @@ -873,7 +874,7 @@ // On Chrome OS, similar UI is displayed in the system tray menu, instead of // this menu. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (chrome::ShouldDisplayManagedUi(browser_->profile())) { AddSeparator(ui::LOWER_SEPARATOR); const int kIconSize = 18; @@ -885,7 +886,7 @@ ui::NativeTheme::kColorId_HighlightedMenuItemForegroundColor, kIconSize)); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) uma_action_recorded_ = false; } @@ -981,7 +982,7 @@ UpdateZoomControls(); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) void AppMenuModel::UpdateSettingsItemState() { const base::ListValue* system_features_disable_list_pref = nullptr; PrefService* const local_state = g_browser_process->local_state(); @@ -999,4 +1000,4 @@ if (index != -1) SetEnabledAt(index, is_enabled); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/toolbar/app_menu_model.h b/chrome/browser/ui/toolbar/app_menu_model.h index d75ba9a..b2d303fe 100644 --- a/chrome/browser/ui/toolbar/app_menu_model.h +++ b/chrome/browser/ui/toolbar/app_menu_model.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "components/prefs/pref_change_registrar.h" #include "content/public/browser/host_zoom_map.h" @@ -198,11 +199,11 @@ // took to select the command. void LogMenuMetrics(int command_id); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Disables/Enables the settings item based on kSystemFeaturesDisableList // pref. void UpdateSettingsItemState(); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // Time menu has been open. Used by LogMenuMetrics() to record the time // to action when the user selects a menu item.
diff --git a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc index 94e10115..da961d1 100644 --- a/chrome/browser/ui/toolbar/app_menu_model_unittest.cc +++ b/chrome/browser/ui/toolbar/app_menu_model_unittest.cc
@@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/defaults.h" #include "chrome/browser/prefs/browser_prefs.h" @@ -24,10 +25,10 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/color_palette.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h" #include "components/policy/core/common/policy_pref_names.h" -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace { @@ -223,7 +224,7 @@ EXPECT_EQ(1, error1->execute_count()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Tests settings menu items is disabled in the app menu when // kSystemFeaturesDisableList is set. TEST_F(AppMenuModelTest, DisableSettingsItem) { @@ -248,4 +249,4 @@ } EXPECT_TRUE(model.IsEnabledAt(index)); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/toolbar/bookmark_sub_menu_model.cc b/chrome/browser/ui/toolbar/bookmark_sub_menu_model.cc index 6f1d426..90788de 100644 --- a/chrome/browser/ui/toolbar/bookmark_sub_menu_model.cc +++ b/chrome/browser/ui/toolbar/bookmark_sub_menu_model.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/grit/generated_resources.h" @@ -40,7 +41,7 @@ } AddCheckItemWithStringId(IDC_SHOW_BOOKMARK_BAR, IDS_SHOW_BOOKMARK_BAR); AddItemWithStringId(IDC_SHOW_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) AddItemWithStringId(IDC_IMPORT_SETTINGS, IDS_IMPORT_SETTINGS_MENU_LABEL); #endif }
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 5924106..f8ff53e 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/ui_features.h" +#include "build/chromeos_buildflags.h" + namespace features { // Enables showing the EV certificate details in the Page Info bubble. @@ -127,7 +129,7 @@ const base::Feature kWebUITabStrip{"WebUITabStrip", base::FEATURE_DISABLED_BY_DEFAULT}; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Enables a warning about connecting to hidden WiFi networks. // https://crbug.com/903908 const base::Feature kHiddenNetworkWarning{"HiddenNetworkWarning", @@ -137,5 +139,5 @@ // for pointing sticks (such as TrackPoints). const base::Feature kSeparatePointingStickSettings{ "SeparatePointingStickSettings", base::FEATURE_DISABLED_BY_DEFAULT}; -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace features
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 8bc3e162..a53e9f1c 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -11,6 +11,7 @@ #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/common/buildflags.h" #include "extensions/buildflags/buildflags.h" @@ -91,10 +92,10 @@ extern const base::Feature kWebUITabStrip; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) extern const base::Feature kHiddenNetworkWarning; extern const base::Feature kSeparatePointingStickSettings; -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace features #endif // CHROME_BROWSER_UI_UI_FEATURES_H_
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc index 3a5697d..3a9de32 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -680,9 +680,11 @@ ->GetProfileAttributesStorage() .GetAllProfilesAttributesSortedByName(); for (ProfileAttributesEntry* profile_entry : profile_entries) { - // The current profile is excluded. - if (profile_entry->GetPath() == browser()->profile()->GetPath()) + // Guest profile and the current profile are excluded. + if (profile_entry->IsGuest() || + profile_entry->GetPath() == browser()->profile()->GetPath()) { continue; + } AddSelectableProfile( ui::ImageModel::FromImage(
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc deleted file mode 100644 index 0410261..0000000 --- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc +++ /dev/null
@@ -1,196 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/profiles/profile_picker_view.h" - -#include "base/check.h" -#include "base/run_loop.h" -#include "base/test/mock_callback.h" -#include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/lifetime/browser_shutdown.h" -#include "chrome/browser/ui/profile_picker.h" -#include "chrome/browser/ui/views/profiles/profile_picker_test_base.h" -#include "chrome/test/base/interactive_test_utils.h" -#include "content/public/browser/notification_source.h" -#include "content/public/test/browser_test.h" -#include "content/public/test/browser_test_utils.h" -#include "content/public/test/test_utils.h" -#include "google_apis/gaia/gaia_urls.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/events/keycodes/dom/dom_key.h" -#include "ui/views/view.h" -#include "ui/views/view_observer.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" - -namespace { - -// Waits until a view is deleted. -class ViewDeletedWaiter : public views::ViewObserver { - public: - explicit ViewDeletedWaiter(views::View* view) { - DCHECK(view); - observation_.Observe(view); - } - ~ViewDeletedWaiter() override = default; - - // Waits until the view is deleted. - void Wait() { run_loop_.Run(); } - - private: - // ViewObserver: - void OnViewIsDeleting(views::View* observed_view) override { - run_loop_.Quit(); - } - - base::RunLoop run_loop_; - base::ScopedObservation<views::View, views::ViewObserver> observation_{this}; -}; - -// Waits until the widget bounds change. -class WidgetBoundsChangeWaiter : public views::WidgetObserver { - public: - explicit WidgetBoundsChangeWaiter(views::Widget* widget) { - DCHECK(widget); - observation_.Observe(widget); - } - - // Waits until the widget bounds change. - void Wait() { run_loop_.Run(); } - - private: - // WidgetObserver: - void OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) override { - run_loop_.Quit(); - } - - base::RunLoop run_loop_; - base::ScopedObservation<views::Widget, views::WidgetObserver> observation_{ - this}; -}; - -} // namespace - -class ProfilePickerInteractiveUiTest : public ProfilePickerTestBase { - public: - ProfilePickerInteractiveUiTest() = default; - ~ProfilePickerInteractiveUiTest() override = default; - - void SendCloseWindowKeyboardCommand() { - // Close window using keyboard. -#if defined(OS_MAC) - // Use Cmd-W on Mac. - bool control = false; - bool shift = false; - bool command = true; -#else - // Use Ctrl-Shift-W on other platforms. - bool control = true; - bool shift = true; - bool command = false; -#endif - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - widget()->GetNativeWindow(), ui::VKEY_W, control, shift, /*alt=*/false, - command)); - } - - void WaitForPickerClosed() { - if (!ProfilePicker::IsOpen()) - return; - ViewDeletedWaiter(view()).Wait(); - ASSERT_FALSE(ProfilePicker::IsOpen()); - } -}; - -// Checks that the main picker view can be closed with keyboard shortcut. -IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, CloseWithKeyboard) { - // Open a new picker. - ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles); - WaitForNewWebView(); - WaitForFirstPaint(web_contents(), GURL("chrome://profile-picker")); - EXPECT_TRUE(ProfilePicker::IsOpen()); - SendCloseWindowKeyboardCommand(); - WaitForPickerClosed(); - // Closing the picker does not exit Chrome. - EXPECT_FALSE(browser_shutdown::IsTryingToQuit()); -} - -#if defined(OS_MAC) -// Checks that Chrome be closed with keyboard shortcut. Only MacOS has a -// keyboard shortcut to exit Chrome. -IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, ExitWithKeyboard) { - // Open a new picker. - ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles); - WaitForNewWebView(); - WaitForFirstPaint(web_contents(), GURL("chrome://profile-picker")); - EXPECT_TRUE(ProfilePicker::IsOpen()); - - content::WindowedNotificationObserver terminate_observer( - chrome::NOTIFICATION_APP_TERMINATING, - content::NotificationService::AllSources()); - // Send Cmd-Q. - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - widget()->GetNativeWindow(), ui::VKEY_Q, /*control=*/false, - /*shift=*/false, /*alt=*/false, /*command=*/true)); - // Check that Chrome is quitting. - terminate_observer.Wait(); - WaitForPickerClosed(); - EXPECT_TRUE(browser_shutdown::IsTryingToQuit()); -} -#endif - -// Checks that the main picker view can switch to full screen. -IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, FullscreenWithKeyboard) { - // Open a new picker. - ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuManageProfiles); - WaitForNewWebView(); - WaitForFirstPaint(web_contents(), GURL("chrome://profile-picker")); - EXPECT_TRUE(ProfilePicker::IsOpen()); - - EXPECT_FALSE(widget()->IsFullscreen()); - WidgetBoundsChangeWaiter bounds_waiter(widget()); - - // Toggle fullscreen with keyboard. -#if defined(OS_MAC) - // Use Cmd-Ctrl-F on Mac. - bool control = true; - bool command = true; - ui::KeyboardCode key_code = ui::VKEY_F; -#else - // Use F11 on other platforms. - bool control = false; - bool command = false; - ui::KeyboardCode key_code = ui::VKEY_F11; -#endif - ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync( - widget()->GetNativeWindow(), key_code, control, /*shift=*/false, - /*alt=*/false, command)); - // Fullscreen causes the bounds of the widget to change. - bounds_waiter.Wait(); - EXPECT_TRUE(widget()->IsFullscreen()); -} - -// Checks that the signin web view is able to process keyboard events. -IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, - CloseSigninWithKeyboard) { - ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuAddNewProfile); - WaitForNewWebView(); - - // Simulate a click on the signin button. - base::MockCallback<base::OnceClosure> switch_failure_callback; - EXPECT_CALL(switch_failure_callback, Run()).Times(0); - ProfilePicker::SwitchToSignIn(SK_ColorRED, switch_failure_callback.Get()); - - // Switch to the signin webview. - WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); - - // Close the picker with the keyboard. - EXPECT_TRUE(ProfilePicker::IsOpen()); - SendCloseWindowKeyboardCommand(); - WaitForPickerClosed(); -}
diff --git a/chrome/browser/ui/views/profiles/profile_picker_test_base.cc b/chrome/browser/ui/views/profiles/profile_picker_test_base.cc deleted file mode 100644 index ac452a3..0000000 --- a/chrome/browser/ui/views/profiles/profile_picker_test_base.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/profiles/profile_picker_test_base.h" - -#include "base/callback.h" -#include "base/run_loop.h" -#include "base/scoped_observation.h" -#include "chrome/browser/ui/profile_picker.h" -#include "chrome/browser/ui/ui_features.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/controls/webview/webview.h" -#include "ui/views/view.h" -#include "ui/views/view_observer.h" -#include "url/gurl.h" - -namespace { - -// Waits until a web view is added as a child view of the given view. -class WebViewAddedWaiter : public views::ViewObserver { - public: - WebViewAddedWaiter( - views::View* top_view, - base::RepeatingCallback<views::WebView*()> current_web_view_getter) - : current_web_view_getter_(current_web_view_getter) { - observation_.Observe(top_view); - } - ~WebViewAddedWaiter() override = default; - - void Wait() { run_loop_.Run(); } - - private: - // ViewObserver: - void OnChildViewAdded(views::View* observed_view, - views::View* child) override { - if (child == current_web_view_getter_.Run()) { - ASSERT_TRUE(child); - run_loop_.Quit(); - } - } - - base::RunLoop run_loop_; - base::RepeatingCallback<views::WebView*()> current_web_view_getter_; - base::ScopedObservation<views::View, views::ViewObserver> observation_{this}; -}; - -// Waits until a first non empty paint for given `url`. -class FirstVisuallyNonEmptyPaintObserver : public content::WebContentsObserver { - public: - explicit FirstVisuallyNonEmptyPaintObserver(content::WebContents* contents, - const GURL& url) - : content::WebContentsObserver(contents), url_(url) {} - - // Waits for the first paint. - void Wait() { - if (IsExitConditionSatisfied()) { - return; - } - run_loop_.Run(); - EXPECT_TRUE(IsExitConditionSatisfied()) - << web_contents()->GetVisibleURL() << " != " << url_; - } - - private: - // WebContentsObserver: - void DidFirstVisuallyNonEmptyPaint() override { - if (web_contents()->GetVisibleURL() == url_) - run_loop_.Quit(); - } - - bool IsExitConditionSatisfied() { - return (web_contents()->GetVisibleURL() == url_ && - web_contents()->CompletedFirstVisuallyNonEmptyPaint()); - } - - base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed}; - GURL url_; -}; - -} // namespace - -ProfilePickerTestBase::ProfilePickerTestBase() { - feature_list_.InitAndEnableFeature(features::kNewProfilePicker); -} - -ProfilePickerTestBase::~ProfilePickerTestBase() = default; - -views::View* ProfilePickerTestBase::view() { - return ProfilePicker::GetViewForTesting(); -} - -views::Widget* ProfilePickerTestBase::widget() { - return view() ? view()->GetWidget() : nullptr; -} - -views::WebView* ProfilePickerTestBase::web_view() { - return ProfilePicker::GetWebViewForTesting(); -} - -void ProfilePickerTestBase::WaitForNewWebView() { - ASSERT_TRUE(view()); - WebViewAddedWaiter(view(), - base::BindRepeating(&ProfilePickerTestBase::web_view, - base::Unretained(this))) - .Wait(); - EXPECT_TRUE(web_view()); -} - -void ProfilePickerTestBase::WaitForFirstPaint(content::WebContents* contents, - const GURL& url) { - DCHECK(contents); - FirstVisuallyNonEmptyPaintObserver(contents, url).Wait(); -} - -content::WebContents* ProfilePickerTestBase::web_contents() { - if (!web_view()) - return nullptr; - return web_view()->GetWebContents(); -}
diff --git a/chrome/browser/ui/views/profiles/profile_picker_test_base.h b/chrome/browser/ui/views/profiles/profile_picker_test_base.h deleted file mode 100644 index 7176045..0000000 --- a/chrome/browser/ui/views/profiles/profile_picker_test_base.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_PICKER_TEST_BASE_H_ -#define CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_PICKER_TEST_BASE_H_ - -#include "base/test/scoped_feature_list.h" -#include "chrome/test/base/in_process_browser_test.h" - -namespace content { -class WebContents; -} - -namespace views { -class View; -class WebView; -class Widget; -} // namespace views - -class GURL; - -class ProfilePickerTestBase : public InProcessBrowserTest { - public: - ProfilePickerTestBase(); - ~ProfilePickerTestBase() override; - - // Returns the ProfilePickerView that is currently displayed. - views::View* view(); - - // Returns the widget associated with the profile picker. - views::Widget* widget(); - - // Returns the internal web view for the profile picker. - views::WebView* web_view(); - - // Waits until a new internal web view has been added to the main picker view. - void WaitForNewWebView(); - - // Waits until the web contents does the first non-empty paint for `url`. - void WaitForFirstPaint(content::WebContents* contents, const GURL& url); - - // Gets the picker's web contents. - content::WebContents* web_contents(); - - private: - base::test::ScopedFeatureList feature_list_; -}; - -#endif // CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_PICKER_TEST_BASE_H_
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc index 3c0a000..dcf67b1 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -10,10 +10,8 @@ #include "base/metrics/histogram_functions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" -#include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" -#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" @@ -26,7 +24,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" -#include "chrome/browser/ui/views/accelerator_table.h" #include "chrome/browser/ui/views/profiles/profile_picker_view_sync_delegate.h" #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h" #include "chrome/browser/ui/webui/signin/profile_picker_ui.h" @@ -55,10 +52,6 @@ #include "ui/views/win/hwnd_util.h" #endif -#if defined(OS_MAC) -#include "chrome/browser/global_keyboard_shortcuts_mac.h" -#endif - namespace { ProfilePickerView* g_profile_picker_view = nullptr; @@ -69,10 +62,6 @@ constexpr base::TimeDelta kExtendedAccountInfoTimeout = base::TimeDelta::FromSeconds(10); -constexpr int kSupportedAcceleratorCommands[] = { - IDC_CLOSE_TAB, IDC_CLOSE_WINDOW, IDC_EXIT, IDC_FULLSCREEN, - IDC_MINIMIZE_WINDOW}; - GURL CreateURLForEntryPoint(ProfilePicker::EntryPoint entry_point) { GURL base_url = GURL(chrome::kChromeUIProfilePickerUrl); switch (entry_point) { @@ -156,7 +145,6 @@ SetButtons(ui::DIALOG_BUTTON_NONE); SetTitle(IDS_PRODUCT_NAME); set_use_custom_frame(false); - ConfigureAccelerators(); // TODO(crbug.com/1063856): Add |RecordDialogCreation|. } @@ -214,11 +202,16 @@ void ProfilePickerView::Init(ProfilePicker::EntryPoint entry_point, Profile* system_profile) { DCHECK_EQ(state_, kInitializing); - CreateWebView(system_profile); - DCHECK(web_view_); + auto web_view = std::make_unique<views::WebView>(system_profile); + web_view->GetWebContents()->SetDelegate(this); // To record metrics using javascript, extensions are needed. extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( - web_view_->GetWebContents()); + web_view->GetWebContents()); + // Set the member before adding to the hieararchy to make it easier for tests + // to detect that a new WebView has been created. + web_view_ = web_view.get(); + AddChildView(std::move(web_view)); + SetLayoutManager(std::make_unique<views::FillLayout>()); CreateDialogWidget(this, nullptr, nullptr); @@ -317,7 +310,13 @@ // Rebuild the view. // TODO(crbug.com/1126913): Add the simple toolbar with the back button. RemoveAllChildViews(true); - CreateWebView(profile); + auto web_view = std::make_unique<views::WebView>(profile); + web_view->GetWebContents()->SetDelegate(this); + // Set the member before adding to the hieararchy to make it easier for tests + // to detect that a new WebView has been created. + web_view_ = web_view.get(); + AddChildView(std::move(web_view)); + SetLayoutManager(std::make_unique<views::FillLayout>()); web_view_->LoadInitialURL(GaiaUrls::GetInstance()->signin_chrome_sync_dice()); web_view_->RequestFocus(); } @@ -361,43 +360,6 @@ return minimum_size; } -bool ProfilePickerView::AcceleratorPressed(const ui::Accelerator& accelerator) { - // Ignore presses of the Escape key. The profile picker may be Chrome's only - // top-level window, in which case we don't want presses of Esc to maybe quit - // the entire browser. This has higher priority than the default dialog Esc - // accelerator (which would otherwise close the window). - if (accelerator.key_code() == ui::VKEY_ESCAPE && - accelerator.modifiers() == ui::EF_NONE) { - return true; - } - - const auto& iter = accelerator_table_.find(accelerator); - DCHECK(iter != accelerator_table_.end()); - int command_id = iter->second; - switch (command_id) { - case IDC_CLOSE_TAB: - case IDC_CLOSE_WINDOW: - // kEscKeyPressed is used although that shortcut is disabled (this is - // Ctrl-Shift-W instead). - GetWidget()->CloseWithReason(views::Widget::ClosedReason::kEscKeyPressed); - break; - case IDC_EXIT: - chrome::AttemptUserExit(); - break; - case IDC_FULLSCREEN: - GetWidget()->SetFullscreen(!GetWidget()->IsFullscreen()); - break; - case IDC_MINIMIZE_WINDOW: - GetWidget()->Minimize(); - break; - default: - NOTREACHED() << "Unexpected command_id: " << command_id; - break; - } - - return true; -} - bool ProfilePickerView::HandleContextMenu( content::RenderFrameHost* render_frame_host, const content::ContextMenuParams& params) { @@ -405,15 +367,6 @@ return true; } -bool ProfilePickerView::HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) { - // Forward the keyboard event to AcceleratorPressed() through the - // FocusManager. - return unhandled_keyboard_event_handler_.HandleKeyboardEvent( - event, GetFocusManager()); -} - void ProfilePickerView::AddNewContents( content::WebContents* source, std::unique_ptr<content::WebContents> new_contents, @@ -573,44 +526,3 @@ DCHECK(browser); std::move(finish_flow_callback).Run(browser); } - -void ProfilePickerView::ConfigureAccelerators() { - // By default, dialog views close when pressing escape. Override this - // behavior as the profile picker should not close in that case. - AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); - - const std::vector<AcceleratorMapping> accelerator_list(GetAcceleratorList()); - for (const auto& entry : accelerator_list) { - if (!base::Contains(kSupportedAcceleratorCommands, entry.command_id)) - continue; - ui::Accelerator accelerator(entry.keycode, entry.modifiers); - accelerator_table_[accelerator] = entry.command_id; - AddAccelerator(accelerator); - } - -#if defined(OS_MAC) - // Check Mac-specific accelerators. Note: Chrome does not support dynamic or - // user-configured accelerators on Mac. Default static accelerators are used - // instead. - for (int command_id : kSupportedAcceleratorCommands) { - ui::Accelerator accelerator; - bool mac_accelerator_found = - GetDefaultMacAcceleratorForCommandId(command_id, &accelerator); - if (mac_accelerator_found) { - accelerator_table_[accelerator] = command_id; - AddAccelerator(accelerator); - } - } -#endif // OS_MAC -} - -void ProfilePickerView::CreateWebView(Profile* profile) { - auto web_view = std::make_unique<views::WebView>(profile); - web_view->GetWebContents()->SetDelegate(this); - web_view->set_allow_accelerators(true); - // Set the member before adding to the hieararchy to make it easier for tests - // to detect that a new WebView has been created. - web_view_ = web_view.get(); - AddChildView(std::move(web_view)); - SetLayoutManager(std::make_unique<views::FillLayout>()); -}
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.h b/chrome/browser/ui/views/profiles/profile_picker_view.h index 9141802..7c470c2 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view.h +++ b/chrome/browser/ui/views/profiles/profile_picker_view.h
@@ -11,7 +11,6 @@ #include "components/keep_alive_registry/scoped_keep_alive.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/web_contents_delegate.h" -#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/window/dialog_delegate.h" @@ -73,7 +72,6 @@ // views::View; gfx::Size GetMinimumSize() const override; - bool AcceleratorPressed(const ui::Accelerator& accelerator) override; // content::WebContentsDelegate: bool HandleContextMenu(content::RenderFrameHost* render_frame_host, @@ -85,9 +83,6 @@ const gfx::Rect& initial_rect, bool user_gesture, bool* was_blocked) override; - bool HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) override; // IdentityManager::Observer: void OnRefreshTokenUpdatedForAccount( @@ -109,22 +104,9 @@ Profile* profile, Profile::CreateStatus profile_create_status); - // Register basic keyboard accelerators such as closing the window (Alt-F4 - // on Windows). - void ConfigureAccelerators(); - - // Creates and configures the internal web view, and adds it as a child view. - void CreateWebView(Profile* profile); - ScopedKeepAlive keep_alive_; State state_ = State::kNotStarted; - // A mapping between accelerators and command IDs. - std::map<ui::Accelerator, int> accelerator_table_; - - // Handler for unhandled key events from renderer. - views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; - // The current WebView object, owned by the view hierarchy. views::WebView* web_view_ = nullptr;
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index f7f4af1..c22da81 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -25,7 +25,6 @@ #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h" #include "chrome/browser/ui/tab_dialogs.h" #include "chrome/browser/ui/ui_features.h" -#include "chrome/browser/ui/views/profiles/profile_picker_test_base.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/test/base/in_process_browser_test.h" @@ -39,12 +38,12 @@ #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_user_settings.h" -#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "google_apis/gaia/gaia_urls.h" #include "third_party/skia/include/core/SkColor.h" -#include "url/gurl.h" +#include "ui/views/view_observer.h" namespace { @@ -70,6 +69,64 @@ return account_info; } +// Waits until a first non empty paint for given `url`. +class FirstVisuallyNonEmptyPaintObserver : public content::WebContentsObserver { + public: + explicit FirstVisuallyNonEmptyPaintObserver(content::WebContents* contents, + const GURL& url) + : content::WebContentsObserver(contents), url_(url) {} + + void DidFirstVisuallyNonEmptyPaint() override { + if (web_contents()->GetVisibleURL() == url_) + run_loop_.Quit(); + } + + void Wait() { + if (IsExitConditionSatisfied()) { + return; + } + run_loop_.Run(); + EXPECT_TRUE(IsExitConditionSatisfied()) + << web_contents()->GetVisibleURL() << " != " << url_; + } + + private: + bool IsExitConditionSatisfied() { + return (web_contents()->GetVisibleURL() == url_ && + web_contents()->CompletedFirstVisuallyNonEmptyPaint()); + } + + base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed}; + GURL url_; +}; + +class WebViewAddedWaiter : public views::ViewObserver { + public: + WebViewAddedWaiter( + views::View* top_view, + base::RepeatingCallback<views::WebView*()> current_web_view_getter) + : current_web_view_getter_(current_web_view_getter) { + observation_.Observe(top_view); + } + ~WebViewAddedWaiter() override = default; + + void Wait() { run_loop_.Run(); } + + private: + // ViewObserver: + void OnChildViewAdded(views::View* observed_view, + views::View* child) override { + if (child == current_web_view_getter_.Run()) { + ASSERT_TRUE(child); + run_loop_.Quit(); + } + } + + base::RunLoop run_loop_; + base::RepeatingCallback<views::WebView*()> current_web_view_getter_; + base::ScopedObservation<views::View, views::ViewObserver> observation_{this}; +}; + class BrowserAddedWaiter : public BrowserListObserver { public: explicit BrowserAddedWaiter(size_t total_count) : total_count_(total_count) { @@ -199,14 +256,15 @@ base::RunLoop* run_loop_; }; -class ProfilePickerCreationFlowBrowserTest : public ProfilePickerTestBase { +class ProfilePickerCreationFlowBrowserTest : public InProcessBrowserTest { public: ProfilePickerCreationFlowBrowserTest() { - feature_list_.InitAndEnableFeature(features::kProfilesUIRevamp); + feature_list_.InitWithFeatures( + {features::kProfilesUIRevamp, features::kNewProfilePicker}, {}); } void SetUpInProcessBrowserTestFixture() override { - ProfilePickerTestBase::SetUpInProcessBrowserTestFixture(); + InProcessBrowserTest::SetUpInProcessBrowserTestFixture(); create_services_subscription_ = BrowserContextDependencyManager::GetInstance() ->RegisterCreateServicesCallbackForTesting( @@ -221,6 +279,26 @@ context, base::BindRepeating(&FakeUserPolicySigninService::Build)); } + views::View* view() { return ProfilePicker::GetViewForTesting(); } + + views::WebView* web_view() { return ProfilePicker::GetWebViewForTesting(); } + + void WaitForNewWebView() { + ASSERT_TRUE(view()); + WebViewAddedWaiter( + view(), + base::BindRepeating(&ProfilePickerCreationFlowBrowserTest::web_view, + base::Unretained(this))) + .Wait(); + EXPECT_TRUE(web_view()); + } + + content::WebContents* web_contents() { + if (!web_view()) + return nullptr; + return web_view()->GetWebContents(); + } + private: base::CallbackListSubscription create_services_subscription_; base::test::ScopedFeatureList feature_list_; @@ -246,8 +324,9 @@ ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileMenuAddNewProfile); WaitForNewWebView(); EXPECT_TRUE(ProfilePicker::IsOpen()); - WaitForFirstPaint(web_contents(), - GURL("chrome://profile-picker/new-profile")); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GURL("chrome://profile-picker/new-profile")) + .Wait(); } IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest, @@ -265,8 +344,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Add an account - simulate a successful Gaia sign-in. Profile* profile_being_created = @@ -285,14 +365,18 @@ // Wait for the sign-in to propagate to the flow, resulting in sync // confirmation screen getting displayed. - WaitForFirstPaint(web_contents(), GURL("chrome://sync-confirmation/")); + FirstVisuallyNonEmptyPaintObserver(web_contents(), + GURL("chrome://sync-confirmation/")) + .Wait(); // Simulate closing the UI with "Yes, I'm in". LoginUIServiceFactory::GetForProfile(profile_being_created) ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")) + .Wait(); // Check expectations when the profile creation flow is done. EXPECT_FALSE(ProfilePicker::IsOpen()); @@ -327,8 +411,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Disable sync by setting the device as managed in prefs. Profile* profile_being_created = @@ -352,8 +437,10 @@ // Wait for the sign-in to propagate to the flow, resulting in new browser // getting opened. Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")) + .Wait(); EXPECT_FALSE(ProfilePicker::IsOpen()); @@ -391,8 +478,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Add an account - simulate a successful Gaia sign-in. Profile* profile_being_created = @@ -409,14 +497,18 @@ // Wait for the sign-in to propagate to the flow, resulting in sync // confirmation screen getting displayed. - WaitForFirstPaint(web_contents(), GURL("chrome://sync-confirmation/")); + FirstVisuallyNonEmptyPaintObserver(web_contents(), + GURL("chrome://sync-confirmation/")) + .Wait(); // Simulate closing the UI with "Yes, I'm in". LoginUIServiceFactory::GetForProfile(profile_being_created) ->SyncConfirmationUIClosed(LoginUIService::CONFIGURE_SYNC_FIRST); Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://settings/syncSetup")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://settings/syncSetup")) + .Wait(); // Check expectations when the profile creation flow is done. EXPECT_FALSE(ProfilePicker::IsOpen()); @@ -452,8 +544,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Simulate clicking on a link that opens in a new window. const GURL kURL("https://foo.google.com"); @@ -468,8 +561,9 @@ // A new pppup browser is displayed (with the specified URL). Browser* new_browser = BrowserAddedWaiter(2u).Wait(); EXPECT_EQ(new_browser->type(), Browser::TYPE_POPUP); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - kURL); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), kURL) + .Wait(); } // TODO(crbug.com/1144065): Flaky on multiple platforms. @@ -512,8 +606,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Add an account - simulate a successful Gaia sign-in. Profile* profile_being_created = @@ -530,8 +625,10 @@ // Instead of sync confirmation, a browser is displayed (with a login error). Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")) + .Wait(); // Check expectations when the profile creation flow is done. EXPECT_FALSE(ProfilePicker::IsOpen()); @@ -562,8 +659,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); Profile* profile_being_created = static_cast<Profile*>(web_view()->GetBrowserContext()); @@ -582,14 +680,18 @@ // Wait for the sign-in to propagate to the flow, resulting in sync // confirmation screen getting displayed. - WaitForFirstPaint(web_contents(), GURL("chrome://sync-confirmation/")); + FirstVisuallyNonEmptyPaintObserver(web_contents(), + GURL("chrome://sync-confirmation/")) + .Wait(); // Simulate closing the UI with "Yes, I'm in". LoginUIServiceFactory::GetForProfile(profile_being_created) ->SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); Browser* new_browser = BrowserAddedWaiter(2u).Wait(); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")) + .Wait(); // Check expectations when the profile creation flow is done. EXPECT_FALSE(ProfilePicker::IsOpen()); @@ -638,8 +740,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Add an account - simulate a successful Gaia sign-in. Profile* profile_being_created = @@ -672,8 +775,10 @@ // The picker should be closed even before the enterprise confirmation but it // is closed asynchronously after opening the browser so after the NTP // renders, it is safe to check. - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://newtab/")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://newtab/")) + .Wait(); EXPECT_FALSE(ProfilePicker::IsOpen()); // Now the sync consent screen is shown, simulate closing the UI with "Yes, @@ -709,8 +814,9 @@ // The DICE navigation happens in a new web view (for the profile being // created), wait for it. WaitForNewWebView(); - WaitForFirstPaint(web_contents(), - GaiaUrls::GetInstance()->signin_chrome_sync_dice()); + FirstVisuallyNonEmptyPaintObserver( + web_contents(), GaiaUrls::GetInstance()->signin_chrome_sync_dice()) + .Wait(); // Add an account - simulate a successful Gaia sign-in. Profile* profile_being_created = @@ -743,8 +849,10 @@ // "Configure sync". LoginUIServiceFactory::GetForProfile(profile_being_created) ->SyncConfirmationUIClosed(LoginUIService::CONFIGURE_SYNC_FIRST); - WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(), - GURL("chrome://settings/syncSetup")); + FirstVisuallyNonEmptyPaintObserver( + new_browser->tab_strip_model()->GetActiveWebContents(), + GURL("chrome://settings/syncSetup")) + .Wait(); // Check expectations when the profile creation flow is done. EXPECT_FALSE(ProfilePicker::IsOpen());
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 2a1a0cd..475acf66 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2459,7 +2459,9 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -#if defined(OS_LINUX) +// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is +// complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) #define MAYBE_DraggingRightExpandsTabStripSize \ DISABLED_DraggingRightExpandsTabStripSize #else
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc index 23d02c8..c71703c 100644 --- a/chrome/browser/ui/views/toolbar/app_menu.cc +++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -474,7 +474,7 @@ InMenuButtonBackground::LEADING_BORDER)); fullscreen_button_->SetAccessibleName(GetAccessibleNameForAppMenuItem( menu_model, fullscreen_index, IDS_ACCNAME_FULLSCREEN, -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // ChromeOS uses a dedicated "fullscreen" media key for fullscreen // mode on most ChromeOS devices which cannot be specified in the // standard way here, so omit the accelerator to avoid providing
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc index 6838d1f..718206a 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/feature_list.h" #include "base/strings/string_piece.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/installable/installable_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/security_state_tab_helper.h" @@ -51,7 +52,7 @@ #include "url/gurl.h" #include "url/origin.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/crostini/crostini_terminal.h" #include "chrome/browser/ui/app_list/icon_standardizer.h" #endif @@ -377,7 +378,7 @@ bool AppBrowserController::ShouldShowTabContextMenuShortcut( int command_id) const { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // TODO(crbug.com/1061822): Generalize ShouldShowTabContextMenuShortcut as // a SystemWebApp capability. if (system_app_type_ == SystemAppType::TERMINAL && @@ -508,7 +509,7 @@ gfx::ImageSkia AppBrowserController::GetFallbackAppIcon() const { gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia(); if (!page_icon.isNull()) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) return app_list::CreateStandardIconImage(page_icon); #endif
diff --git a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc index 030ce983..aa94f8d 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/run_loop.h" #include "base/test/bind.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/themes/custom_theme_supplier.h" @@ -245,7 +246,7 @@ } // App Popups are only used on Chrome OS. See https://crbug.com/1060917. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(AppBrowserControllerBrowserTest, WhiteThemeForSystemAppPopup) { InstallAndLaunchMockPopup(); @@ -268,7 +269,7 @@ } #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) IN_PROC_BROWSER_TEST_F(AppBrowserControllerBrowserTest, InitialBounds) { InstallAndLaunchMockApp(); EXPECT_EQ(app_browser_->window()->GetBounds(), gfx::Rect(64, 64, 652, 484));
diff --git a/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc b/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc index 1f8dd96..b8692634 100644 --- a/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc +++ b/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -234,7 +235,7 @@ // Tests that iframes can't dynamically load mixed content in a regular browser // tab, when the iframe was created in a PWA window. // https://crbug.com/1087382: Flaky on Windows, CrOS and ASAN -#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(ADDRESS_SANITIZER) +#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(ADDRESS_SANITIZER) #define MAYBE_IFrameDynamicMixedContentInPWAOpenInChrome \ DISABLED_IFrameDynamicMixedContentInPWAOpenInChrome #else
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc index dffb5f3c..0a81b98 100644 --- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc +++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -14,6 +14,7 @@ #include "base/metrics/histogram_functions.h" #include "base/optional.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_metrics.h" #include "chrome/browser/apps/app_service/launch_utils.h" @@ -36,7 +37,7 @@ #include "ui/base/window_open_disposition.h" #include "ui/display/types/display_constants.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #endif @@ -51,7 +52,7 @@ // alternative. if (profile->IsSystemProfile()) return nullptr; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (chromeos::ProfileHelper::IsSigninProfile(profile)) return nullptr; #endif @@ -258,7 +259,7 @@ } } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // LaunchSystemWebApp may be called with a profile associated with an // inactive (background) desktop (e.g. when multiple users are logged in). // Here we move the newly created browser window (or the existing one on the
diff --git a/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc b/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc index 5f5d9fe..a63c595 100644 --- a/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc +++ b/chrome/browser/ui/web_applications/test/system_web_app_ui_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" #include "base/test/gtest_util.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" @@ -29,7 +30,7 @@ #include "content/public/test/browser_test.h" #include "content/public/test/test_navigation_observer.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/login/login_manager_test.h" @@ -442,7 +443,7 @@ EXPECT_FALSE(app_browser->app_controller()->ShouldShowCustomTabBar()); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Use LoginManagerTest here instead of SystemWebAppManagerBrowserTest, because // it's less complicated to add SWA to LoginManagerTest than adding multi-logins // to SWA browsertest. @@ -567,14 +568,14 @@ MultiUserWindowManagerHelper::GetInstance()->IsWindowOnDesktopOfUser( browser2->window()->GetNativeWindow(), account_id2_)); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // The following tests are disabled in DCHECK builds. LaunchSystemWebApp DCHECKs // if the wrong profile is used. EXPECT_DCHECK_DEATH (or its variants) aren't // reliable in browsertests, so we don't test this. This is okay because these // tests are used to verify that in release builds, LaunchSystemWebApp doesn't // crash and behaves reasonably (pick an appropriate profile). -#if defined(OS_CHROMEOS) && !DCHECK_IS_ON() +#if BUILDFLAG(IS_CHROMEOS_ASH) && !DCHECK_IS_ON() using SystemWebAppLaunchProfileBrowserTest = SystemWebAppManagerBrowserTest; IN_PROC_BROWSER_TEST_P(SystemWebAppLaunchProfileBrowserTest, @@ -646,12 +647,12 @@ EXPECT_TRUE(result_browser->profile()->IsGuestSession()); EXPECT_TRUE(result_browser->profile()->IsPrimaryOTRProfile()); } -#endif // defined(OS_CHROMEOS) && !DCHECK_IS_ON() +#endif // BUILDFLAG(IS_CHROMEOS_ASH) && !DCHECK_IS_ON() INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_ALL_INSTALL_TYPES_P( SystemWebAppLinkCaptureBrowserTest); -#if defined(OS_CHROMEOS) && !DCHECK_IS_ON() +#if BUILDFLAG(IS_CHROMEOS_ASH) && !DCHECK_IS_ON() INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_ALL_INSTALL_TYPES_P( SystemWebAppLaunchProfileBrowserTest);
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index 1a9aba7..668ec1d 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -7,6 +7,7 @@ #include "base/callback_helpers.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/profiles/profile.h" @@ -27,7 +28,7 @@ #include "ui/gfx/image/image.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/apps/apk_web_app_service.h" namespace { @@ -68,7 +69,7 @@ return display == DisplayMode::kWindowControlsOverlay; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) bool WebAppBrowserController::ShouldShowCustomTabBar() const { if (AppBrowserController::ShouldShowCustomTabBar()) return true; @@ -92,7 +93,7 @@ browser()->window()->UpdateCustomTabBarVisibility(should_show_cct, false /* animate */); } -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) void WebAppBrowserController::OnWebAppUninstalled(const AppId& app_id) { if (HasAppId() && app_id == GetAppId()) @@ -113,7 +114,7 @@ return *app_icon_; app_icon_ = GetFallbackAppIcon(); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon) && apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile( browser()->profile())) { @@ -279,7 +280,7 @@ void WebAppBrowserController::PerformDigitalAssetLinkVerification( Browser* browser) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) asset_link_handler_ = std::make_unique<digital_asset_links::DigitalAssetLinksHandler>( browser->profile()->GetURLLoaderFactory());
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h index da81bcf..5f0b88d2 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.h +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -13,6 +13,7 @@ #include "base/optional.h" #include "base/scoped_observer.h" #include "base/strings/string16.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/browser/web_applications/components/app_registrar.h" #include "chrome/browser/web_applications/components/app_registrar_observer.h" @@ -21,7 +22,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/image/image_skia.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/installable/digital_asset_links/digital_asset_links_handler.h" #endif @@ -69,9 +70,9 @@ bool IsHostedApp() const override; bool IsWindowControlsOverlayEnabled() const override; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) bool ShouldShowCustomTabBar() const override; -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // AppRegistrarObserver: void OnWebAppUninstalled(const AppId& app_id) override; @@ -95,22 +96,22 @@ void OnReadIcon(const SkBitmap& bitmap); void PerformDigitalAssetLinkVerification(Browser* browser); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) void OnRelationshipCheckComplete( digital_asset_links::RelationshipCheckResult result); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) WebAppProvider& provider_; mutable base::Optional<gfx::ImageSkia> app_icon_; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // The result of digital asset link verification of the web app. // Only used for web-only TWAs installed through the Play Store. base::Optional<bool> is_verified_; std::unique_ptr<digital_asset_links::DigitalAssetLinksHandler> asset_link_handler_; -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) ScopedObserver<AppRegistrar, AppRegistrarObserver> registrar_observer_{this};
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 09e6e2e..d844d5c5 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/sessions/tab_restore_service_factory.h" #include "chrome/browser/themes/custom_theme_supplier.h" @@ -56,7 +57,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #endif @@ -698,7 +699,7 @@ int index = -1; const bool found = app_menu_model->GetModelAndIndexForCommandId( WebAppMenuModel::kUninstallAppCommandId, &model, &index); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) EXPECT_FALSE(found); #else EXPECT_TRUE(found); @@ -711,7 +712,7 @@ MENU_ACTION_UNINSTALL_APP, 1); tester.ExpectUniqueSample("WrenchMenu.MenuAction", MENU_ACTION_UNINSTALL_APP, 1); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // Tests that both installing a PWA and creating a shortcut app are disabled for @@ -800,7 +801,7 @@ EXPECT_EQ(1, user_action_tester.GetActionCount("InstallWebAppFromMenu")); EXPECT_EQ(0, user_action_tester.GetActionCount("CreateShortcut")); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Apps on Chrome OS should not be pinned after install. EXPECT_FALSE(ChromeLauncherController::instance()->IsAppPinned(app_id)); #endif
diff --git a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc index 217caea..40997f7 100644 --- a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_launch_params.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" @@ -33,7 +34,7 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/web_launch/file_handling_expiry.mojom-test-utils.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chrome/browser/chromeos/file_manager/file_manager_test_util.h" #endif @@ -557,7 +558,7 @@ content::EvalJs(web_content, "window.launchParams.files[0].name")); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // End-to-end test to ensure the file handler is registered on ChromeOS when the // extension system is initialized. Gives more coverage than the unit tests for @@ -598,4 +599,4 @@ EXPECT_EQ(0u, tasks.size()); } -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/web_applications/web_app_menu_model.cc b/chrome/browser/ui/web_applications/web_app_menu_model.cc index abccc4e7..a380027 100644 --- a/chrome/browser/ui/web_applications/web_app_menu_model.cc +++ b/chrome/browser/ui/web_applications/web_app_menu_model.cc
@@ -6,6 +6,7 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" +#include "build/chromeos_buildflags.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/media/router/media_router_feature.h" #include "chrome/browser/profiles/profile.h" @@ -67,7 +68,7 @@ // Chrome OS's app list is prominent enough to not need a separate uninstall // option in the app menu. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) DCHECK(browser()->app_controller()); if (browser()->app_controller()->IsInstalled()) { AddSeparator(ui::NORMAL_SEPARATOR); @@ -77,7 +78,7 @@ ui::EscapeMenuLabelAmpersands( browser()->app_controller()->GetAppShortName()))); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) AddSeparator(ui::LOWER_SEPARATOR); CreateZoomMenu();
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc index af0d2c3..8acc7d7 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -8,6 +8,7 @@ #include "base/callback.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/extensions/launch_util.h" @@ -27,7 +28,7 @@ #include "extensions/browser/app_sorting.h" #include "extensions/browser/extension_system.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/shelf_model.h" #include "chrome/browser/ui/app_list/app_list_syncable_service.h" #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" @@ -92,7 +93,7 @@ // static bool WebAppUiManager::ShouldHideAppFromUser(const AppId& app_id) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return app_list::HideInLauncherById(app_id); #else return false; @@ -183,7 +184,7 @@ continue; if (!has_migrated) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Grid position in app list. auto* app_list_syncable_service = app_list::AppListSyncableServiceFactory::GetForProfile(profile_); @@ -233,7 +234,7 @@ } bool WebAppUiManagerImpl::CanAddAppToQuickLaunchBar() const { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) return true; #else return false; @@ -242,13 +243,13 @@ void WebAppUiManagerImpl::AddAppToQuickLaunchBar(const AppId& app_id) { DCHECK(CanAddAppToQuickLaunchBar()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // ChromeLauncherController does not exist in unit tests. if (auto* controller = ChromeLauncherController::instance()) { controller->PinAppWithID(app_id); controller->UpdateV1AppState(app_id); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } bool WebAppUiManagerImpl::IsInAppWindow(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc index 5b18af7..1f618c7 100644 --- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/barrier_closure.h" #include "base/test/bind.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/built_in_chromeos_apps.h" @@ -20,7 +21,7 @@ #include "content/public/test/browser_test.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/public/cpp/app_list/internal_app_id_constants.h" #include "chrome/browser/ui/app_list/app_list_model_updater.h" #include "chrome/browser/ui/app_list/app_list_syncable_service.h" @@ -147,7 +148,7 @@ } } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Tests that app migrations use the UI preferences of the replaced app but only // if it's present. IN_PROC_BROWSER_TEST_F(WebAppUiManagerImplBrowserTest, DoubleMigration) { @@ -187,6 +188,6 @@ ->item_pin_ordinal.ToDebugString(), "positionnew"); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace web_app
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index f20f17c..fa7db71 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -1094,6 +1094,14 @@ return; } + // We need a special case for USB printers here. We cannot query them + // directly, so we have to fall back to manual configuration here. + if (printer->IsUsbProtocol()) { + RejectJavascriptCallback(base::Value(callback_id), + *GetCupsPrinterInfo(*printer)); + return; + } + // The mDNS record doesn't guarantee we can setup the printer. Query it to // see if we want to try IPP. auto address = printer->GetHostAndPort();
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc index b31cbad..e265dbd2 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -655,14 +655,21 @@ void PeopleHandler::HandleSignout(const base::ListValue* args) { bool delete_profile = false; args->GetBoolean(0, &delete_profile); + base::FilePath profile_path = profile_->GetPath(); if (!signin_util::IsUserSignoutAllowedForProfile(profile_)) { // If the user cannot signout, the profile must be destroyed. DCHECK(delete_profile); } else { + Browser* browser = + chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); + if (browser) { + browser->signin_view_controller()->ShowGaiaLogoutTab( + signin_metrics::SourceForRefreshTokenOperation::kSettings_Signout); + } + auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_); if (identity_manager->HasPrimaryAccount()) { - signin_metrics::SignoutDelete delete_metric = delete_profile ? signin_metrics::SignoutDelete::DELETED : signin_metrics::SignoutDelete::KEEPING; @@ -672,6 +679,8 @@ // (see http://crbug.com/1068978). If the account is already invalid, drop // the token now (because it's already invalid on the web, so the Gaia // logout tab won't affect it, see http://crbug.com/1114646). + // This operation may delete the current browser that owns |this| if force + // signin is enabled. See https://crbug.com/1153120. identity_manager->GetPrimaryAccountMutator()->ClearPrimaryAccount( signin::PrimaryAccountMutator::ClearAccountsAction::kDefault, signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, delete_metric); @@ -679,18 +688,12 @@ DCHECK(!delete_profile) << "Deleting the profile should only be offered the user is syncing."; } - - Browser* browser = - chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); - if (!browser) - return; - - browser->signin_view_controller()->ShowGaiaLogoutTab( - signin_metrics::SourceForRefreshTokenOperation::kSettings_Signout); } + // CAUTION: |this| may be deleted at this point. + if (delete_profile) { - webui::DeleteProfileAtPath(profile_->GetPath(), + webui::DeleteProfileAtPath(profile_path, ProfileMetrics::DELETE_PROFILE_SETTINGS); } }
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc index 81f0c0cd..47fe176 100644 --- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc +++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -552,6 +552,8 @@ const int avatar_icon_size = kProfileCardAvatarSize * web_ui()->GetDeviceScaleFactor(); for (const ProfileAttributesEntry* entry : entries) { + if (entry->IsGuest()) + continue; auto profile_entry = std::make_unique<base::DictionaryValue>(); profile_entry->SetKey("profilePath", util::FilePathToValue(entry->GetPath()));
diff --git a/chrome/browser/ui/window_sizer/window_sizer.cc b/chrome/browser/ui/window_sizer/window_sizer.cc index 00062ca..c1cc1ac 100644 --- a/chrome/browser/ui/window_sizer/window_sizer.cc +++ b/chrome/browser/ui/window_sizer/window_sizer.cc
@@ -23,7 +23,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/browser/ui/window_sizer/window_sizer_chromeos.h" #endif @@ -113,7 +113,7 @@ } if (window) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) if (window->IsVisible()) *bounds = window->GetRestoredBounds(); #else @@ -163,7 +163,7 @@ ui::WindowShowState* show_state) { DCHECK(bounds); DCHECK(show_state); -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) WindowSizerChromeOS sizer(std::move(state_provider), browser); #else WindowSizer sizer(std::move(state_provider), browser); @@ -363,10 +363,10 @@ // static display::Display WindowSizer::GetDisplayForNewWindow(const gfx::Rect& bounds) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) // Prefer the display where the user last activated a window. return display::Screen::GetScreen()->GetDisplayForNewWindows(); #else return display::Screen::GetScreen()->GetDisplayMatching(bounds); -#endif // defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) }
diff --git a/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc b/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc index f7cc74f..e8ffe58 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_chromeos.cc
@@ -15,7 +15,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" -#if !BUILDFLAG(IS_LACROS) +#if !BUILDFLAG(IS_CHROMEOS_LACROS) #include "chrome/common/pref_names.h" #endif @@ -26,7 +26,7 @@ constexpr int kForceMaximizeWidthLimit = 1366; bool ShouldForceMaximizeOnFirstRun(Profile* profile) { -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) // TODO(https://crbug.com/1110548): Support the ForceMaximizeOnFirstRun policy // in lacros-chrome. return false;
diff --git a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc index e9a9e04..42021ff5 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc
@@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/ui/browser.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/testing_profile.h" @@ -121,7 +122,7 @@ #if !defined(OS_MAC) -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Passing null for the browser parameter of GetWindowBounds makes the test skip // all Ash-specific logic, so there's no point running this on Chrome OS. TEST(WindowSizerTestCommon, @@ -309,7 +310,7 @@ EXPECT_EQ("50,368 500x400", window_bounds.ToString()); } } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) // Test that the window is sized appropriately for the first run experience // where the default window bounds calculation is invoked.
diff --git a/chrome/browser/ui/zoom/zoom_controller_browsertest.cc b/chrome/browser/ui/zoom/zoom_controller_browsertest.cc index 9322098..c8a1d98 100644 --- a/chrome/browser/ui/zoom/zoom_controller_browsertest.cc +++ b/chrome/browser/ui/zoom/zoom_controller_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/process/kill.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -243,7 +244,7 @@ TestResetOnNavigation(ZoomController::ZOOM_MODE_MANUAL); } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Regression test: crbug.com/438979. IN_PROC_BROWSER_TEST_F(ZoomControllerBrowserTest, SettingsZoomAfterSigninWorks) { @@ -297,4 +298,4 @@ zoom_controller->SetZoomLevel(new_zoom_level); zoom_change_watcher.Wait(); } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index a7756c46..d7083bf 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1606434328-b11de2c42e4be1904f18040e42ebddef022e94a9.profdata +chrome-linux-master-1606477302-0eef9df5e342eba3f05f76047fdfe0ee5f85aae6.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 6deb4a5..8d1f476 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1606434328-d20b89cbb7113eb50f7c91d68d6760cac88c7639.profdata +chrome-mac-master-1606477302-630adcad5e4cdcdcf2ef51c7b233ac57a3e03250.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 4a409ad..29b5c65 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1606423711-20b7d89425d1187d62c0bed2d0c51ba670083d7c.profdata +chrome-win32-master-1606467421-254a879f9aaee24c27bff0d45dc43b60000cc185.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index b008469..3a8b5c2ed 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1606445966-4a9759f3f64c32ba89411261d898a8870ebcc34b.profdata +chrome-win64-master-1606467421-5bc9c94caac3d987cc9eb0508bb0c4216e88e158.profdata
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm index 2b5c5c3..11147c9 100644 --- a/chrome/common/service_process_util_mac.mm +++ b/chrome/common/service_process_util_mac.mm
@@ -281,7 +281,7 @@ return false; } if (!executable_watcher.Watch( - executable_path, false, + executable_path, base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&ExecFilePathWatcherCallback::NotifyPathChanged, base::Owned(callback.release())))) { DLOG(ERROR) << "executable_watcher.watch " << executable_path.value();
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 569cddb..da0f325 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3183,7 +3183,8 @@ [ "../browser/site_isolation/spellcheck_per_process_browsertest.cc" ] } - if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { + if (is_win || is_mac || + ((is_linux || is_chromeos_lacros) && !is_chromeos_lacros)) { sources += [ "../browser/ui/views/profiles/profile_picker_view_browsertest.cc" ] } @@ -6319,12 +6320,6 @@ "../browser/password_manager/password_manager_signin_intercept_test_helper.h", ] } - if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { - sources += [ - "../browser/ui/views/profiles/profile_picker_test_base.cc", - "../browser/ui/views/profiles/profile_picker_test_base.h", - ] - } } proto_library("test_proto") { @@ -6808,12 +6803,6 @@ sources += [ "../browser/ui/views/frame/webui_tab_strip_interactive_uitest.cc" ] } - - if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { - sources += [ - "../browser/ui/views/profiles/profile_picker_interactive_uitest.cc", - ] - } } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java index ec2abf63..be13b4b 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -5,31 +5,30 @@ package org.chromium.chrome.test; import android.app.Activity; +import android.app.Instrumentation; import android.content.ComponentName; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.test.InstrumentationRegistry; import android.support.test.internal.runner.listener.InstrumentationResultPrinter; +import android.support.test.rule.ActivityTestRule; import android.view.Menu; -import androidx.annotation.NonNull; - import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Rule; import org.junit.runner.Description; import org.junit.runners.model.Statement; +import org.chromium.base.ActivityState; import org.chromium.base.ApplicationStatus; +import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.CommandLine; -import org.chromium.base.ThreadUtils; -import org.chromium.base.test.BaseActivityTestRule; +import org.chromium.base.Log; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.Criteria; import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.ScalableTimeout; -import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -42,9 +41,7 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuTestSupport; import org.chromium.chrome.test.util.ChromeApplicationTestUtils; import org.chromium.chrome.test.util.ChromeTabUtils; -import org.chromium.chrome.test.util.NewTabPageTestUtils; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.infobars.InfoBar; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; @@ -62,13 +59,14 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Custom {@link ActivityTestRule} for test using {@link ChromeActivity}. * * @param <T> The {@link Activity} class under test. */ -public class ChromeActivityTestRule<T extends ChromeActivity> extends BaseActivityTestRule<T> { +public class ChromeActivityTestRule<T extends ChromeActivity> extends ActivityTestRule<T> { private static final String TAG = "ChromeATR"; // The number of ms to wait for the rendering activity to be started. @@ -77,13 +75,20 @@ private static final long OMNIBOX_FIND_SUGGESTION_TIMEOUT_MS = 10 * 1000; private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler; + private Class<T> mChromeActivityClass; + private T mSetActivity; private String mCurrentTestName; @Rule private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule(); protected ChromeActivityTestRule(Class<T> activityClass) { - super(activityClass); + this(activityClass, false); + } + + protected ChromeActivityTestRule(Class<T> activityClass, boolean initialTouchMode) { + super(activityClass, initialTouchMode, false); + mChromeActivityClass = activityClass; } @Override @@ -130,11 +135,13 @@ return ACTIVITY_START_TIMEOUT_MS; } - // This has to be here or getActivity will return a T that extends Activity, not a T that - // extends ChromeActivity. + // TODO(yolandyan): remove this once startActivityCompletely is refactored out of + // ChromeActivityTestRule @Override - @SuppressWarnings("RedundantOverride") public T getActivity() { + if (mSetActivity != null) { + return mSetActivity; + } return super.getActivity(); } @@ -145,14 +152,6 @@ } /** - * TODO(https://crbug.com/1146574): This only exists here because legacy ActivityTestRule - * inherited from UiThreadTestRule. This function should be removed. - */ - public void runOnUiThread(Runnable r) { - ThreadUtils.runOnUiThreadBlocking(r); - } - - /** * @return The {@link AppMenuCoordinator} for the activity. */ public AppMenuCoordinator getAppMenuCoordinator() { @@ -197,37 +196,49 @@ } /** - * Similar to #launchActivity(Intent), but waits for the Activity tab to be initialized. + * Invokes {@link Instrumentation#startActivitySync(Intent)} and sets the + * test case's activity to the result. See the documentation for + * {@link Instrumentation#startActivitySync(Intent)} on the timing of the + * return, but generally speaking the activity's "onCreate" has completed + * and the activity's main looper has become idle. + * + * TODO(yolandyan): very similar to ActivityTestRule#launchActivity(Intent), + * yet small differences remains (e.g. launchActivity() uses FLAG_ACTIVITY_NEW_TASK while + * startActivityCompletely doesn't), need to refactor and use only launchActivity + * after the JUnit4 migration */ public void startActivityCompletely(Intent intent) { - DeferredStartupHandler.setExpectingActivityStartupForTesting(); - launchActivity(intent); - waitForActivityNativeInitializationComplete(); - - CriteriaHelper.pollUiThread( - () -> getActivity().getActivityTab() != null, "Tab never selected/initialized."); - Tab tab = getActivity().getActivityTab(); - - ChromeTabUtils.waitForTabPageLoaded(tab, (String) null); - - if (tab != null && UrlUtilities.isNTPUrl(ChromeTabUtils.getUrlStringOnUiThread(tab)) - && !getActivity().isInOverviewMode()) { - NewTabPageTestUtils.waitForNtpLoaded(tab); - } - - Assert.assertTrue("Deferred startup never completed. Did you try to start an Activity " - + "that was already started?", - DeferredStartupHandler.waitForDeferredStartupCompleteForTesting( - ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))); - - Assert.assertNotNull(tab); - Assert.assertNotNull(tab.getView()); - } - - @Override - public void launchActivity(@NonNull Intent startIntent) { Features.ensureCommandLineIsUpToDate(); - super.launchActivity(startIntent); + + final CallbackHelper activityCallback = new CallbackHelper(); + final AtomicReference<T> activityRef = new AtomicReference<>(); + ActivityStateListener stateListener = new ActivityStateListener() { + @SuppressWarnings("unchecked") + @Override + public void onActivityStateChange(Activity activity, int newState) { + if (newState == ActivityState.RESUMED) { + if (!mChromeActivityClass.isAssignableFrom(activity.getClass())) return; + + activityRef.set((T) activity); + activityCallback.notifyCalled(); + ApplicationStatus.unregisterActivityStateListener(this); + } + } + }; + ApplicationStatus.registerStateListenerForAllActivities(stateListener); + + try { + InstrumentationRegistry.getInstrumentation().startActivitySync(intent); + activityCallback.waitForCallback("Activity did not start as expected", 0); + T activity = activityRef.get(); + Assert.assertNotNull("Activity reference is null.", activity); + setActivity(activity); + Log.d(TAG, "startActivityCompletely <<"); + } catch (TimeoutException e) { + throw new RuntimeException(e); + } finally { + ApplicationStatus.unregisterActivityStateListener(stateListener); + } } /** @@ -461,6 +472,10 @@ return getActivity().getWindowAndroid().getKeyboardDelegate(); } + public void setActivity(T chromeActivity) { + mSetActivity = chromeActivity; + } + /** * Waits for an Activity of the given class to be started. * @return The Activity.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java index 65e683d..cc708d7 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
@@ -20,8 +20,11 @@ import org.chromium.base.Log; import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CriteriaHelper; +import org.chromium.base.test.util.ScalableTimeout; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.browser.DeferredStartupHandler; import org.chromium.chrome.browser.omnibox.UrlBar; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabCreationState; @@ -33,6 +36,7 @@ import org.chromium.chrome.test.util.MenuUtils; import org.chromium.chrome.test.util.NewTabPageTestUtils; import org.chromium.chrome.test.util.WaitForFocusHelper; +import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.content_public.browser.test.util.TestThreadUtils; import java.util.concurrent.TimeoutException; @@ -109,7 +113,31 @@ */ public void startMainActivityFromIntent(Intent intent, String url) { prepareUrlIntent(intent, url); + + DeferredStartupHandler.setExpectingActivityStartupForTesting(); startActivityCompletely(intent); + waitForActivityNativeInitializationComplete(); + + CriteriaHelper.pollUiThread( + () -> getActivity().getActivityTab() != null, "Tab never selected/initialized."); + Tab tab = getActivity().getActivityTab(); + + ChromeTabUtils.waitForTabPageLoaded(tab, (String) null); + + if (tab != null && UrlUtilities.isNTPUrl(ChromeTabUtils.getUrlStringOnUiThread(tab)) + && !getActivity().isInOverviewMode()) { + NewTabPageTestUtils.waitForNtpLoaded(tab); + } + + Assert.assertTrue("Deferred startup never completed. Did you try to start an Activity " + + "that was already started?", + DeferredStartupHandler.waitForDeferredStartupCompleteForTesting( + ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL))); + + Assert.assertNotNull(tab); + Assert.assertNotNull(tab.getView()); + + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java index dba985d0..e401694 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
@@ -39,7 +39,6 @@ super(); mActivityTestRule = activityTestRule; mClearAllTabState = clearAllTabState; - mActivityTestRule.setFinishActivity(false); } @Override
diff --git a/chromecast/media/cma/backend/cast_audio_json.cc b/chromecast/media/cma/backend/cast_audio_json.cc index c2b2780..b38e0b7b 100644 --- a/chromecast/media/cma/backend/cast_audio_json.cc +++ b/chromecast/media/cma/backend/cast_audio_json.cc
@@ -98,7 +98,8 @@ void CastAudioJsonProviderImpl::FileWatcher::SetTuningChangedCallback( TuningChangedCallback callback) { watcher_.Watch( - CastAudioJson::GetFilePathForTuning(), false /* recursive */, + CastAudioJson::GetFilePathForTuning(), + base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&ReadFileRunCallback, std::move(callback))); }
diff --git a/chromeos/components/account_manager/account_manager.cc b/chromeos/components/account_manager/account_manager.cc index aa28a6c..d33563e 100644 --- a/chromeos/components/account_manager/account_manager.cc +++ b/chromeos/components/account_manager/account_manager.cc
@@ -27,11 +27,11 @@ #include "chromeos/constants/chromeos_pref_names.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "third_party/protobuf/src/google/protobuf/message_lite.h" @@ -661,8 +661,9 @@ return nullptr; } - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory_, it->second.token); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory_, it->second.token); } bool AccountManager::IsTokenAvailable(
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index 2a28417..12fb2b5 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -49,12 +49,16 @@ "actions/highlight_element_action.h", "actions/navigate_action.cc", "actions/navigate_action.h", + "actions/perform_on_single_element_action.cc", + "actions/perform_on_single_element_action.h", "actions/popup_message_action.cc", "actions/popup_message_action.h", "actions/presave_generated_password_action.cc", "actions/presave_generated_password_action.h", "actions/prompt_action.cc", "actions/prompt_action.h", + "actions/release_elements_action.cc", + "actions/release_elements_action.h", "actions/save_generated_password_action.cc", "actions/save_generated_password_action.h", "actions/select_option_action.cc", @@ -284,6 +288,8 @@ "mock_website_login_manager.h", "service/mock_service.cc", "service/mock_service.h", + "web/fake_element_store.cc", + "web/fake_element_store.h", "web/mock_web_controller.cc", "web/mock_web_controller.h", ] @@ -314,9 +320,11 @@ "actions/generate_password_for_form_field_action_unittest.cc", "actions/get_element_status_action_unittest.cc", "actions/highlight_element_action_unittest.cc", + "actions/perform_on_single_element_action_unittest.cc", "actions/popup_message_action_unittest.cc", "actions/presave_generated_password_action_unittest.cc", "actions/prompt_action_unittest.cc", + "actions/release_elements_action_unittest.cc", "actions/save_generated_password_action_unittest.cc", "actions/select_option_action_unittest.cc", "actions/set_attribute_action_unittest.cc",
diff --git a/components/autofill_assistant/browser/actions/action.cc b/components/autofill_assistant/browser/actions/action.cc index c2a842a..7e657f36 100644 --- a/components/autofill_assistant/browser/actions/action.cc +++ b/components/autofill_assistant/browser/actions/action.cc
@@ -170,6 +170,48 @@ case ActionProto::ActionInfoCase::kGetElementStatus: out << "GetElementStatus"; break; + case ActionProto::ActionInfoCase::kScrollIntoView: + out << "ScrollIntoView"; + break; + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeInteractive: + out << "WaitForDocumentToBecomeInteractive"; + break; + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeComplete: + out << "WaitForDocumentToBecomeComplete"; + break; + case ActionProto::ActionInfoCase::kSendClickEvent: + out << "SendClickEvent"; + break; + case ActionProto::ActionInfoCase::kSendTapEvent: + out << "SendTapEvent"; + break; + case ActionProto::ActionInfoCase::kJsClick: + out << "JsClick"; + break; + case ActionProto::ActionInfoCase::kSendKeystrokeEvents: + out << "SendKeystrokeEvents"; + break; + case ActionProto::ActionInfoCase::kSetFieldValue: + out << "SetFieldValue"; + break; + case ActionProto::ActionInfoCase::kSetElementAttribute: + out << "SetElementAttribute"; + break; + case ActionProto::ActionInfoCase::kSelectFieldValue: + out << "SelectFieldValue"; + break; + case ActionProto::ActionInfoCase::kFocusField: + out << "FocusField"; + break; + case ActionProto::ActionInfoCase::kWaitForElementToBecomeStable: + out << "WaitForElementToBecomeStable"; + break; + case ActionProto::ActionInfoCase::kCheckElementIsOnTop: + out << "CheckElementIsOnTop"; + break; + case ActionProto::ActionInfoCase::kReleaseElements: + out << "ReleaseElements"; + break; case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: out << "ACTION_INFO_NOT_SET"; break;
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h index 237bbb3..6a1b882 100644 --- a/components/autofill_assistant/browser/actions/action_delegate.h +++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -43,6 +43,7 @@ struct CollectUserDataOptions; class ElementStore; class UserAction; +class WebController; class WebsiteLoginManager; // Action delegate called when processing actions. @@ -284,8 +285,8 @@ const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback) = 0; - // Sets the keyboard focus to |element| and inputs the specified codepoints. - // Returns the result through |callback|. + // Inputs the specified codepoints into |element|. Expects the |element| to + // have focus. Returns the result through |callback|. virtual void SendKeyboardInput( const std::vector<UChar32>& codepoints, int key_press_delay_in_millisecond, @@ -381,6 +382,9 @@ // Get the ElementStore. virtual ElementStore* GetElementStore() const = 0; + // Get the WebController. + virtual WebController* GetWebController() const = 0; + // Returns the e-mail address that corresponds to the access token or an empty // string. virtual std::string GetEmailAddressForAccessTokenAccount() = 0;
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util.cc b/components/autofill_assistant/browser/actions/action_delegate_util.cc index 727e07aa..cc0ba7d 100644 --- a/components/autofill_assistant/browser/actions/action_delegate_util.cc +++ b/components/autofill_assistant/browser/actions/action_delegate_util.cc
@@ -11,6 +11,7 @@ #include "components/autofill_assistant/browser/selector.h" #include "components/autofill_assistant/browser/service.pb.h" #include "components/autofill_assistant/browser/string_conversions_util.h" +#include "components/autofill_assistant/browser/user_data_util.h" #include "components/autofill_assistant/browser/web/element_finder.h" namespace autofill_assistant { @@ -159,6 +160,37 @@ std::move(done), OkClientStatus()); } +void PerformWithTextValue( + const ActionDelegate* delegate, + const TextValue& text_value, + base::OnceCallback<void(const std::string&, + const ElementFinder::Result&, + base::OnceCallback<void(const ClientStatus&)>)> + perform, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> done) { + std::string value; + switch (text_value.value_case()) { + case TextValue::kText: + value = text_value.text(); + break; + case TextValue::kAutofillValue: { + ClientStatus autofill_status = GetFormattedAutofillValue( + text_value.autofill_value(), delegate->GetUserData(), &value); + if (!autofill_status.ok()) { + std::move(done).Run(autofill_status); + return; + } + break; + } + case TextValue::VALUE_NOT_SET: + std::move(done).Run(ClientStatus(INVALID_ACTION)); + return; + } + + std::move(perform).Run(value, element, std::move(done)); +} + void AddOptionalStep(OptionalStep optional_step, ElementActionCallback step, ElementActionVector* actions) {
diff --git a/components/autofill_assistant/browser/actions/action_delegate_util.h b/components/autofill_assistant/browser/actions/action_delegate_util.h index 5aa27bb..1c1a916 100644 --- a/components/autofill_assistant/browser/actions/action_delegate_util.h +++ b/components/autofill_assistant/browser/actions/action_delegate_util.h
@@ -78,10 +78,25 @@ std::move(element_result), std::move(done))); } +// Run all |perform_actions| sequentially. Breaks the execution on any error +// and executes the |done| callback with the final status. void PerformAll(std::unique_ptr<ElementActionVector> perform_actions, const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> done); +// Resolve the |text_value| and run the |perform| callback. Run the |done| +// callback with an error status if the |text_value| could not be resolved. +// Run the |done| callback with the result status of |perform| otherwise. +void PerformWithTextValue( + const ActionDelegate* delegate, + const TextValue& text_value, + base::OnceCallback<void(const std::string&, + const ElementFinder::Result&, + base::OnceCallback<void(const ClientStatus&)>)> + perform, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> done); + // Adds an optional step to the |actions|. If the step is |SKIP_STEP|, it does // not add it. For |REPORT_STEP_RESULT| it adds the step ignoring a potential // failure. For |REQUIRE_STEP_SUCCESS| it binds the step as is.
diff --git a/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/components/autofill_assistant/browser/actions/collect_user_data_action.cc index c4d5c5c..87910d2 100644 --- a/components/autofill_assistant/browser/actions/collect_user_data_action.cc +++ b/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -507,6 +507,10 @@ login_option.preselection_priority(), login_option.has_info_popup() ? base::make_optional(login_option.info_popup()) + : base::nullopt, + login_option.has_edit_button_content_description() + ? base::make_optional( + login_option.edit_button_content_description()) : base::nullopt); login_details_map_.emplace( identifier, std::make_unique<LoginDetails>( @@ -807,6 +811,10 @@ : -1, login_option.has_info_popup() ? base::make_optional(login_option.info_popup()) + : base::nullopt, + login_option.has_edit_button_content_description() + ? base::make_optional( + login_option.edit_button_content_description()) : base::nullopt}; collect_user_data_options_->login_choices.emplace_back( std::move(choice));
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h index ec06bfe..2eca1de 100644 --- a/components/autofill_assistant/browser/actions/mock_action_delegate.h +++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -21,6 +21,8 @@ #include "components/autofill_assistant/browser/user_data.h" #include "components/autofill_assistant/browser/web/element_finder.h" #include "components/autofill_assistant/browser/web/element_store.h" +#include "components/autofill_assistant/browser/web/fake_element_store.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "testing/gmock/include/gmock/gmock.h" namespace autofill_assistant { @@ -269,6 +271,7 @@ MOCK_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*()); MOCK_METHOD0(GetWebsiteLoginManager, WebsiteLoginManager*()); MOCK_METHOD0(GetWebContents, content::WebContents*()); + MOCK_CONST_METHOD0(GetWebController, WebController*()); MOCK_METHOD0(GetEmailAddressForAccessTokenAccount, std::string()); MOCK_METHOD0(GetLocale, std::string()); MOCK_METHOD1(SetDetails, void(std::unique_ptr<Details> details)); @@ -378,7 +381,7 @@ ElementStore* GetElementStore() const override { if (!element_store_) { - element_store_ = std::make_unique<ElementStore>(nullptr); + element_store_ = std::make_unique<FakeElementStore>(); } return element_store_.get(); }
diff --git a/components/autofill_assistant/browser/actions/perform_on_single_element_action.cc b/components/autofill_assistant/browser/actions/perform_on_single_element_action.cc new file mode 100644 index 0000000..166ad88 --- /dev/null +++ b/components/autofill_assistant/browser/actions/perform_on_single_element_action.cc
@@ -0,0 +1,122 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/actions/perform_on_single_element_action.h" + +#include "base/callback_helpers.h" +#include "base/memory/ptr_util.h" +#include "base/time/time.h" +#include "components/autofill_assistant/browser/dom_action.pb.h" +#include "components/autofill_assistant/browser/web/element_store.h" + +namespace autofill_assistant { + +PerformOnSingleElementAction::PerformOnSingleElementAction( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + bool element_is_optional, + PerformAction perform, + PerformTimedAction perform_timed) + : Action(delegate, proto), + client_id_(client_id.identifier()), + element_is_optional_(element_is_optional), + perform_(std::move(perform)), + perform_timed_(std::move(perform_timed)) {} + +PerformOnSingleElementAction::~PerformOnSingleElementAction() = default; + +// static +std::unique_ptr<PerformOnSingleElementAction> +PerformOnSingleElementAction::WithClientId(ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformAction perform) { + return base::WrapUnique(new PerformOnSingleElementAction( + delegate, proto, client_id, + /* element_is_optional= */ false, std::move(perform), + /* perform_timed= */ base::NullCallback())); +} + +// static +std::unique_ptr<PerformOnSingleElementAction> +PerformOnSingleElementAction::WithOptionalClientId( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformAction perform) { + return base::WrapUnique(new PerformOnSingleElementAction( + delegate, proto, client_id, + /* element_is_optional= */ true, std::move(perform), + /* perform_timed= */ base::NullCallback())); +} + +// static +std::unique_ptr<PerformOnSingleElementAction> +PerformOnSingleElementAction::WithClientIdTimed( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformTimedAction perform_timed) { + return base::WrapUnique(new PerformOnSingleElementAction( + delegate, proto, client_id, + /* element_is_optional= */ false, + /* perform= */ base::NullCallback(), std::move(perform_timed))); +} + +// static +std::unique_ptr<PerformOnSingleElementAction> +PerformOnSingleElementAction::WithOptionalClientIdTimed( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformTimedAction perform_timed) { + return base::WrapUnique(new PerformOnSingleElementAction( + delegate, proto, client_id, + /* element_is_optional= */ true, + /* perform= */ base::NullCallback(), std::move(perform_timed))); +} + +void PerformOnSingleElementAction::InternalProcessAction( + ProcessActionCallback callback) { + callback_ = std::move(callback); + if (client_id_.empty() && !element_is_optional_) { + EndAction(ClientStatus(INVALID_ACTION)); + return; + } + + if (!client_id_.empty()) { + ClientStatus status = + delegate_->GetElementStore()->GetElement(client_id_, &element_); + if (!status.ok()) { + EndAction(status); + return; + } + } + + if (perform_) { + std::move(perform_).Run( + element_, base::BindOnce(&PerformOnSingleElementAction::EndAction, + weak_ptr_factory_.GetWeakPtr())); + return; + } else if (perform_timed_) { + std::move(perform_timed_) + .Run(element_, + base::BindOnce( + &PerformOnSingleElementAction::OnWaitForElementTimed, + weak_ptr_factory_.GetWeakPtr(), + base::BindOnce(&PerformOnSingleElementAction::EndAction, + weak_ptr_factory_.GetWeakPtr()))); + return; + } + NOTREACHED(); + EndAction(ClientStatus(INVALID_ACTION)); +} + +void PerformOnSingleElementAction::EndAction(const ClientStatus& status) { + UpdateProcessedAction(status); + std::move(callback_).Run(std::move(processed_action_proto_)); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/perform_on_single_element_action.h b/components/autofill_assistant/browser/actions/perform_on_single_element_action.h new file mode 100644 index 0000000..f8238058 --- /dev/null +++ b/components/autofill_assistant/browser/actions/perform_on_single_element_action.h
@@ -0,0 +1,82 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PERFORM_ON_SINGLE_ELEMENT_ACTION_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PERFORM_ON_SINGLE_ELEMENT_ACTION_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "components/autofill_assistant/browser/actions/action.h" +#include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/dom_action.pb.h" +#include "components/autofill_assistant/browser/web/element_finder.h" + +namespace autofill_assistant { + +// An action that runs the registered execution callback on a single element +// previously stored. No additional parameters are provided when running the +// callback. +class PerformOnSingleElementAction : public Action { + public: + using PerformAction = + base::OnceCallback<void(const ElementFinder::Result&, + base::OnceCallback<void(const ClientStatus&)>)>; + using PerformTimedAction = base::OnceCallback<void( + const ElementFinder::Result&, + base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>)>; + + ~PerformOnSingleElementAction() override; + + PerformOnSingleElementAction(const PerformOnSingleElementAction&) = delete; + PerformOnSingleElementAction& operator=(const PerformOnSingleElementAction&) = + delete; + + static std::unique_ptr<PerformOnSingleElementAction> WithClientId( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformAction perform); + static std::unique_ptr<PerformOnSingleElementAction> WithOptionalClientId( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformAction perform); + static std::unique_ptr<PerformOnSingleElementAction> WithClientIdTimed( + ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformTimedAction perform); + static std::unique_ptr<PerformOnSingleElementAction> + WithOptionalClientIdTimed(ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + PerformTimedAction perform); + + private: + PerformOnSingleElementAction(ActionDelegate* delegate, + const ActionProto& proto, + const ClientIdProto& client_id, + bool element_is_optional, + PerformAction perform, + PerformTimedAction perform_timed); + + // Overrides Action: + void InternalProcessAction(ProcessActionCallback callback) override; + + void EndAction(const ClientStatus& status); + + ElementFinder::Result element_; + ProcessActionCallback callback_; + + std::string client_id_; + bool element_is_optional_ = false; + PerformAction perform_; + PerformTimedAction perform_timed_; + + base::WeakPtrFactory<PerformOnSingleElementAction> weak_ptr_factory_{this}; +}; + +} // namespace autofill_assistant +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_PERFORM_ON_SINGLE_ELEMENT_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/perform_on_single_element_action_unittest.cc b/components/autofill_assistant/browser/actions/perform_on_single_element_action_unittest.cc new file mode 100644 index 0000000..45b98e3 --- /dev/null +++ b/components/autofill_assistant/browser/actions/perform_on_single_element_action_unittest.cc
@@ -0,0 +1,136 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/actions/perform_on_single_element_action.h" + +#include "base/test/gmock_callback_support.h" +#include "base/test/mock_callback.h" +#include "components/autofill_assistant/browser/action_value.pb.h" +#include "components/autofill_assistant/browser/actions/action_test_utils.h" +#include "components/autofill_assistant/browser/actions/mock_action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/dom_action.pb.h" +#include "components/autofill_assistant/browser/web/element_finder.h" +#include "components/autofill_assistant/browser/web/element_store.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace autofill_assistant { +namespace { + +using ::base::test::RunOnceCallback; +using ::testing::_; +using ::testing::Pointee; +using ::testing::Property; +using ::testing::SaveArgPointee; + +const char kClientId[] = "1"; + +class PerformOnSingleElementActionTest : public testing::Test { + public: + PerformOnSingleElementActionTest() {} + + void SetUp() override { client_id_.set_identifier(kClientId); } + + protected: + MockActionDelegate mock_action_delegate_; + base::MockCallback<Action::ProcessActionCallback> callback_; + base::MockCallback<PerformOnSingleElementAction::PerformAction> perform_; + base::MockCallback<PerformOnSingleElementAction::PerformTimedAction> + perform_timed_; + UserData user_data_; + ActionProto action_proto_; + ClientIdProto client_id_; +}; + +TEST_F(PerformOnSingleElementActionTest, EmptyClientIdFails) { + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION)))); + EXPECT_CALL(perform_, Run(_, _)).Times(0); + + ClientIdProto client_id; + auto action = PerformOnSingleElementAction::WithClientId( + &mock_action_delegate_, action_proto_, client_id, perform_.Get()); + action->ProcessAction(callback_.Get()); +} + +TEST_F(PerformOnSingleElementActionTest, OptionalEmptyClientIdDoesNotFail) { + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED)))); + EXPECT_CALL(perform_, Run(_, _)) + .WillOnce(RunOnceCallback<1>(OkClientStatus())); + + ClientIdProto client_id; + auto action = PerformOnSingleElementAction::WithOptionalClientId( + &mock_action_delegate_, action_proto_, client_id, perform_.Get()); + action->ProcessAction(callback_.Get()); +} + +TEST_F(PerformOnSingleElementActionTest, + OptionalEmptyClientIdDoesNotFailForTimed) { + ProcessedActionProto capture; + EXPECT_CALL(callback_, Run(_)).WillOnce(testing::SaveArgPointee<0>(&capture)); + EXPECT_CALL(perform_timed_, Run(_, _)) + .WillOnce(RunOnceCallback<1>(OkClientStatus(), + base::TimeDelta::FromSeconds(1))); + + ClientIdProto client_id; + auto action = PerformOnSingleElementAction::WithOptionalClientIdTimed( + &mock_action_delegate_, action_proto_, client_id, perform_timed_.Get()); + action->ProcessAction(callback_.Get()); + + EXPECT_EQ(ACTION_APPLIED, capture.status()); + EXPECT_EQ(1000, capture.timing_stats().wait_time_ms()); +} + +TEST_F(PerformOnSingleElementActionTest, FailsIfElementDoesNotExist) { + EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status, + CLIENT_ID_RESOLUTION_FAILED)))); + EXPECT_CALL(perform_, Run(_, _)).Times(0); + + auto action = PerformOnSingleElementAction::WithClientId( + &mock_action_delegate_, action_proto_, client_id_, perform_.Get()); + action->ProcessAction(callback_.Get()); +} + +TEST_F(PerformOnSingleElementActionTest, PerformsAndEnds) { + ElementFinder::Result element; + element.dom_object.object_data.object_id = "id"; + mock_action_delegate_.GetElementStore()->AddElement(kClientId, + element.dom_object); + + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED)))); + EXPECT_CALL(perform_, Run(EqualsElement(element), _)) + .WillOnce(RunOnceCallback<1>(OkClientStatus())); + + auto action = PerformOnSingleElementAction::WithClientId( + &mock_action_delegate_, action_proto_, client_id_, perform_.Get()); + action->ProcessAction(callback_.Get()); +} + +TEST_F(PerformOnSingleElementActionTest, PerformsTimedAndEnds) { + ElementFinder::Result element; + element.dom_object.object_data.object_id = "id"; + mock_action_delegate_.GetElementStore()->AddElement(kClientId, + element.dom_object); + + ProcessedActionProto capture; + EXPECT_CALL(callback_, Run(_)).WillOnce(testing::SaveArgPointee<0>(&capture)); + EXPECT_CALL(perform_timed_, Run(EqualsElement(element), _)) + .WillOnce(RunOnceCallback<1>(OkClientStatus(), + base::TimeDelta::FromSeconds(1))); + + auto action = PerformOnSingleElementAction::WithClientIdTimed( + &mock_action_delegate_, action_proto_, client_id_, perform_timed_.Get()); + action->ProcessAction(callback_.Get()); + + EXPECT_EQ(ACTION_APPLIED, capture.status()); + EXPECT_EQ(1000, capture.timing_stats().wait_time_ms()); +} + +} // namespace +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/release_elements_action.cc b/components/autofill_assistant/browser/actions/release_elements_action.cc new file mode 100644 index 0000000..558dda78 --- /dev/null +++ b/components/autofill_assistant/browser/actions/release_elements_action.cc
@@ -0,0 +1,39 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/actions/release_elements_action.h" + +#include "base/callback.h" +#include "components/autofill_assistant/browser/action_value.pb.h" +#include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_store.h" + +namespace autofill_assistant { + +ReleaseElementsAction::ReleaseElementsAction(ActionDelegate* delegate, + const ActionProto& proto) + : Action(delegate, proto) { + DCHECK(proto_.has_release_elements()); +} + +ReleaseElementsAction::~ReleaseElementsAction() {} + +void ReleaseElementsAction::InternalProcessAction( + ProcessActionCallback callback) { + process_action_callback_ = std::move(callback); + + for (const auto& client_id : proto_.release_elements().client_ids()) { + delegate_->GetElementStore()->RemoveElement(client_id.identifier()); + } + + EndAction(ClientStatus(ACTION_APPLIED)); +} + +void ReleaseElementsAction::EndAction(const ClientStatus& status) { + UpdateProcessedAction(status); + std::move(process_action_callback_).Run(std::move(processed_action_proto_)); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/release_elements_action.h b/components/autofill_assistant/browser/actions/release_elements_action.h new file mode 100644 index 0000000..9f0c29d4 --- /dev/null +++ b/components/autofill_assistant/browser/actions/release_elements_action.h
@@ -0,0 +1,37 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_RELEASE_ELEMENTS_ACTION_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_RELEASE_ELEMENTS_ACTION_H_ + +#include "base/memory/weak_ptr.h" +#include "components/autofill_assistant/browser/actions/action.h" +#include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" + +namespace autofill_assistant { + +// An action to release elements from the store. +class ReleaseElementsAction : public Action { + public: + explicit ReleaseElementsAction(ActionDelegate* delegate, + const ActionProto& proto); + ~ReleaseElementsAction() override; + + ReleaseElementsAction(const ReleaseElementsAction&) = delete; + ReleaseElementsAction& operator=(const ReleaseElementsAction&) = delete; + + private: + // Overrides Action: + void InternalProcessAction(ProcessActionCallback callback) override; + + void EndAction(const ClientStatus& status); + + ProcessActionCallback process_action_callback_; + + base::WeakPtrFactory<ReleaseElementsAction> weak_ptr_factory_{this}; +}; + +} // namespace autofill_assistant +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_RELEASE_ELEMEMENTS_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/release_elements_action_unittest.cc b/components/autofill_assistant/browser/actions/release_elements_action_unittest.cc new file mode 100644 index 0000000..700aad9f1 --- /dev/null +++ b/components/autofill_assistant/browser/actions/release_elements_action_unittest.cc
@@ -0,0 +1,94 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/actions/release_elements_action.h" + +#include "base/test/gmock_callback_support.h" +#include "base/test/mock_callback.h" +#include "components/autofill_assistant/browser/action_value.pb.h" +#include "components/autofill_assistant/browser/actions/mock_action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_store.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace autofill_assistant { +namespace { + +using ::base::test::RunOnceCallback; +using ::testing::_; +using ::testing::Pointee; +using ::testing::Property; + +const char kClientId[] = "1"; +const char kOtherClientId[] = "2"; + +class ReleaseElementsActionTest : public testing::Test { + public: + ReleaseElementsActionTest() {} + + void SetUp() override { + ClientIdProto client_id; + client_id.set_identifier(kClientId); + *proto_.add_client_ids() = client_id; + } + + void Run() { + ActionProto action_proto; + *action_proto.mutable_release_elements() = proto_; + ReleaseElementsAction action(&mock_action_delegate_, action_proto); + action.ProcessAction(callback_.Get()); + } + + protected: + MockActionDelegate mock_action_delegate_; + base::MockCallback<Action::ProcessActionCallback> callback_; + ReleaseElementsProto proto_; +}; + +TEST_F(ReleaseElementsActionTest, ReleasesSingleElement) { + ElementFinder::Result element; + element.dom_object.object_data.object_id = "id"; + mock_action_delegate_.GetElementStore()->AddElement(kClientId, + element.dom_object); + + EXPECT_TRUE(mock_action_delegate_.GetElementStore()->HasElement(kClientId)); + + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED)))); + + Run(); + + EXPECT_FALSE(mock_action_delegate_.GetElementStore()->HasElement(kClientId)); +} + +TEST_F(ReleaseElementsActionTest, ReleasesMultipleElements) { + ClientIdProto client_id_2; + client_id_2.set_identifier(kOtherClientId); + *proto_.add_client_ids() = client_id_2; + + ElementFinder::Result element; + element.dom_object.object_data.object_id = "id"; + mock_action_delegate_.GetElementStore()->AddElement(kClientId, + element.dom_object); + mock_action_delegate_.GetElementStore()->AddElement(kOtherClientId, + element.dom_object); + + EXPECT_TRUE(mock_action_delegate_.GetElementStore()->HasElement(kClientId)); + EXPECT_TRUE( + mock_action_delegate_.GetElementStore()->HasElement(kOtherClientId)); + + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED)))); + + Run(); + + EXPECT_FALSE(mock_action_delegate_.GetElementStore()->HasElement(kClientId)); + EXPECT_FALSE( + mock_action_delegate_.GetElementStore()->HasElement(kOtherClientId)); +} + +} // namespace +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/dom_action.proto b/components/autofill_assistant/browser/dom_action.proto index 5b0f1813..3533297 100644 --- a/components/autofill_assistant/browser/dom_action.proto +++ b/components/autofill_assistant/browser/dom_action.proto
@@ -30,13 +30,13 @@ optional int32 timeout_in_ms = 2; } -message WaitForElementToBecomeStable { +message WaitForElementToBecomeStableProto { optional ClientIdProto client_id = 1; optional int32 stable_check_max_rounds = 2 [default = 50]; optional int32 stable_check_interval_ms = 3 [default = 200]; } -message CheckElementIsOnTop { +message CheckElementIsOnTopProto { optional ClientIdProto client_id = 1; }
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc index 7ea264e..712fc85 100644 --- a/components/autofill_assistant/browser/protocol_utils.cc +++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -8,6 +8,7 @@ #include "base/feature_list.h" #include "base/logging.h" +#include "components/autofill_assistant/browser/actions/action_delegate_util.h" #include "components/autofill_assistant/browser/actions/click_action.h" #include "components/autofill_assistant/browser/actions/collect_user_data_action.h" #include "components/autofill_assistant/browser/actions/configure_bottom_sheet_action.h" @@ -17,9 +18,11 @@ #include "components/autofill_assistant/browser/actions/get_element_status_action.h" #include "components/autofill_assistant/browser/actions/highlight_element_action.h" #include "components/autofill_assistant/browser/actions/navigate_action.h" +#include "components/autofill_assistant/browser/actions/perform_on_single_element_action.h" #include "components/autofill_assistant/browser/actions/popup_message_action.h" #include "components/autofill_assistant/browser/actions/presave_generated_password_action.h" #include "components/autofill_assistant/browser/actions/prompt_action.h" +#include "components/autofill_assistant/browser/actions/release_elements_action.h" #include "components/autofill_assistant/browser/actions/save_generated_password_action.h" #include "components/autofill_assistant/browser/actions/select_option_action.h" #include "components/autofill_assistant/browser/actions/set_attribute_action.h" @@ -40,6 +43,7 @@ #include "components/autofill_assistant/browser/actions/wait_for_dom_action.h" #include "components/autofill_assistant/browser/actions/wait_for_navigation_action.h" #include "components/autofill_assistant/browser/service.pb.h" +#include "components/autofill_assistant/browser/web/web_controller.h" #include "url/gurl.h" namespace autofill_assistant { @@ -233,6 +237,102 @@ return std::make_unique<PresaveGeneratedPasswordAction>(delegate, action); case ActionProto::ActionInfoCase::kGetElementStatus: return std::make_unique<GetElementStatusAction>(delegate, action); + case ActionProto::ActionInfoCase::kScrollIntoView: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.scroll_into_view().client_id(), + base::BindOnce(&WebController::ScrollIntoView, + delegate->GetWebController()->GetWeakPtr())); + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeInteractive: + return PerformOnSingleElementAction::WithOptionalClientIdTimed( + delegate, action, + action.wait_for_document_to_become_interactive().client_id(), + base::BindOnce(&ActionDelegate::WaitUntilDocumentIsInReadyState, + delegate->GetWeakPtr(), + base::TimeDelta::FromMilliseconds( + action.wait_for_document_to_become_interactive() + .timeout_in_ms()), + DOCUMENT_INTERACTIVE)); + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeComplete: + return PerformOnSingleElementAction::WithOptionalClientIdTimed( + delegate, action, + action.wait_for_document_to_become_complete().client_id(), + base::BindOnce(&ActionDelegate::WaitUntilDocumentIsInReadyState, + delegate->GetWeakPtr(), + base::TimeDelta::FromMilliseconds( + action.wait_for_document_to_become_complete() + .timeout_in_ms()), + DOCUMENT_COMPLETE)); + case ActionProto::ActionInfoCase::kSendClickEvent: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.send_click_event().client_id(), + base::BindOnce(&ActionDelegate::ClickOrTapElement, + delegate->GetWeakPtr(), ClickType::CLICK)); + case ActionProto::ActionInfoCase::kSendTapEvent: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.send_tap_event().client_id(), + base::BindOnce(&ActionDelegate::ClickOrTapElement, + delegate->GetWeakPtr(), ClickType::TAP)); + case ActionProto::ActionInfoCase::kJsClick: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.js_click().client_id(), + base::BindOnce(&ActionDelegate::ClickOrTapElement, + delegate->GetWeakPtr(), ClickType::JAVASCRIPT)); + case ActionProto::ActionInfoCase::kSendKeystrokeEvents: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.send_keystroke_events().client_id(), + base::BindOnce( + &action_delegate_util::PerformWithTextValue, delegate, + action.send_keystroke_events().value(), + base::BindOnce(&WebController::SendTextInput, + delegate->GetWebController()->GetWeakPtr(), + action.send_keystroke_events().delay_in_ms()))); + case ActionProto::ActionInfoCase::kSetFieldValue: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.set_field_value().client_id(), + base::BindOnce(&action_delegate_util::PerformWithTextValue, delegate, + action.set_field_value().value(), + base::BindOnce(&ActionDelegate::SetValueAttribute, + delegate->GetWeakPtr()))); + case ActionProto::ActionInfoCase::kSetElementAttribute: { + std::vector<std::string> attributes; + for (const auto& attribute : action.set_element_attribute().attribute()) { + attributes.emplace_back(attribute); + } + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.set_element_attribute().client_id(), + base::BindOnce(&action_delegate_util::PerformWithTextValue, delegate, + action.set_element_attribute().value(), + base::BindOnce(&ActionDelegate::SetAttribute, + delegate->GetWeakPtr(), attributes))); + } + case ActionProto::ActionInfoCase::kSelectFieldValue: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.select_field_value().client_id(), + base::BindOnce(&WebController::SelectFieldValue, + delegate->GetWebController()->GetWeakPtr())); + case ActionProto::ActionInfoCase::kFocusField: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.focus_field().client_id(), + base::BindOnce(&WebController::FocusField, + delegate->GetWebController()->GetWeakPtr())); + case ActionProto::ActionInfoCase::kWaitForElementToBecomeStable: + return PerformOnSingleElementAction::WithClientIdTimed( + delegate, action, + action.wait_for_element_to_become_stable().client_id(), + base::BindOnce(&ActionDelegate::WaitUntilElementIsStable, + delegate->GetWeakPtr(), + action.wait_for_element_to_become_stable() + .stable_check_max_rounds(), + base::TimeDelta::FromMilliseconds( + action.wait_for_element_to_become_stable() + .stable_check_interval_ms()))); + case ActionProto::ActionInfoCase::kCheckElementIsOnTop: + return PerformOnSingleElementAction::WithClientId( + delegate, action, action.check_element_is_on_top().client_id(), + base::BindOnce(&WebController::CheckOnTop, + delegate->GetWebController()->GetWeakPtr())); + case ActionProto::ActionInfoCase::kReleaseElements: + return std::make_unique<ReleaseElementsAction>(delegate, action); case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: { VLOG(1) << "Encountered action with ACTION_INFO_NOT_SET"; return std::make_unique<UnsupportedAction>(delegate, action);
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc index b053823..bf75ab4 100644 --- a/components/autofill_assistant/browser/script_executor.cc +++ b/components/autofill_assistant/browser/script_executor.cc
@@ -215,6 +215,20 @@ case ActionProto::ActionInfoCase::kConfigureUiState: case ActionProto::ActionInfoCase::kPresaveGeneratedPassword: case ActionProto::ActionInfoCase::kGetElementStatus: + case ActionProto::ActionInfoCase::kScrollIntoView: + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeInteractive: + case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeComplete: + case ActionProto::ActionInfoCase::kSendClickEvent: + case ActionProto::ActionInfoCase::kSendTapEvent: + case ActionProto::ActionInfoCase::kJsClick: + case ActionProto::ActionInfoCase::kSendKeystrokeEvents: + case ActionProto::ActionInfoCase::kSetFieldValue: + case ActionProto::ActionInfoCase::kSetElementAttribute: + case ActionProto::ActionInfoCase::kSelectFieldValue: + case ActionProto::ActionInfoCase::kFocusField: + case ActionProto::ActionInfoCase::kWaitForElementToBecomeStable: + case ActionProto::ActionInfoCase::kCheckElementIsOnTop: + case ActionProto::ActionInfoCase::kReleaseElements: case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: return false; } @@ -781,6 +795,10 @@ return delegate_->GetElementStore(); } +WebController* ScriptExecutor::GetWebController() const { + return delegate_->GetWebController(); +} + std::string ScriptExecutor::GetEmailAddressForAccessTokenAccount() { return delegate_->GetEmailAddressForAccessTokenAccount(); }
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h index 6389fd6..89931c0 100644 --- a/components/autofill_assistant/browser/script_executor.h +++ b/components/autofill_assistant/browser/script_executor.h
@@ -31,6 +31,7 @@ class ElementStore; class UserModel; class WaitForDocumentOperation; +class WebController; // Class to execute an assistant script. class ScriptExecutor : public ActionDelegate, @@ -263,6 +264,7 @@ WebsiteLoginManager* GetWebsiteLoginManager() override; content::WebContents* GetWebContents() override; ElementStore* GetElementStore() const override; + WebController* GetWebController() const override; std::string GetEmailAddressForAccessTokenAccount() override; std::string GetLocale() override; void SetDetails(std::unique_ptr<Details> details) override;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index a1c3a13..096e5f8 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -619,6 +619,22 @@ ConfigureUiStateProto configure_ui_state = 54; PresaveGeneratedPasswordProto presave_generated_password = 55; GetElementStatusProto get_element_status = 56; + ScrollIntoViewProto scroll_into_view = 57; + WaitForDocumentToBecomeInteractiveProto + wait_for_document_to_become_interactive = 58; + WaitForDocumentToBecomeCompleteProto wait_for_document_to_become_complete = + 59; + SendClickEventProto send_click_event = 60; + SendTapEventProto send_tap_event = 61; + JsClickProto js_click = 62; + SendKeystrokeEventsProto send_keystroke_events = 63; + SetFieldValueProto set_field_value = 64; + SetElementAttributeProto set_element_attribute = 65; + SelectFieldValueProto select_field_value = 66; + FocusFieldProto focus_field = 67; + WaitForElementToBecomeStableProto wait_for_element_to_become_stable = 68; + CheckElementIsOnTopProto check_element_is_on_top = 69; + ReleaseElementsProto release_elements = 70; } // Set to true to make the client remove any contextual information if the @@ -1942,6 +1958,14 @@ optional string sublabel = 7; optional string sublabel_accessibility_hint = 8; + // The optional content description of the edit button. There are three + // possible states: + // - unset: the content description will be inferred from the button. + // - set to empty string: this button is not important for a11y. + // - set to non-empty string: the button will have the specified content + // description. + optional string edit_button_content_description = 10; + // If the option was chosen, this payload will be returned to the server. optional bytes payload = 1; @@ -1956,6 +1980,8 @@ LoginOptionCustomProto custom = 4; LoginOptionPasswordManagerProto password_manager = 5; } + + reserved 9; } // The title for the login selection (e.g., 'Login details for <domain>'). optional string section_title = 1; @@ -2775,3 +2801,7 @@ optional bool expected_empty_match = 7; } } + +message ReleaseElementsProto { + repeated ClientIdProto client_ids = 1; +}
diff --git a/components/autofill_assistant/browser/service/service_request_sender_impl.cc b/components/autofill_assistant/browser/service/service_request_sender_impl.cc index f147669d..eabeb73 100644 --- a/components/autofill_assistant/browser/service/service_request_sender_impl.cc +++ b/components/autofill_assistant/browser/service/service_request_sender_impl.cc
@@ -74,7 +74,8 @@ #ifdef DEBUG loader->SetAllowHttpErrorResults(true); #endif - loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + auto* const loader_ptr = loader.get(); + loader_ptr->DownloadToStringOfUnboundedSizeUntilCrashAndDie( content::BrowserContext::GetDefaultStoragePartition(context) ->GetURLLoaderFactoryForBrowserProcess() .get(),
diff --git a/components/autofill_assistant/browser/user_data.cc b/components/autofill_assistant/browser/user_data.cc index 9e9c18e..6267839 100644 --- a/components/autofill_assistant/browser/user_data.cc +++ b/components/autofill_assistant/browser/user_data.cc
@@ -15,13 +15,15 @@ const std::string& _sublabel, const base::Optional<std::string>& _sublabel_accessibility_hint, int _preselect_priority, - const base::Optional<InfoPopupProto>& _info_popup) + const base::Optional<InfoPopupProto>& _info_popup, + const base::Optional<std::string>& _edit_button_content_description) : identifier(_identifier), label(_label), sublabel(_sublabel), sublabel_accessibility_hint(_sublabel_accessibility_hint), preselect_priority(_preselect_priority), - info_popup(_info_popup) {} + info_popup(_info_popup), + edit_button_content_description(_edit_button_content_description) {} LoginChoice::LoginChoice(const LoginChoice& another) = default; LoginChoice::~LoginChoice() = default;
diff --git a/components/autofill_assistant/browser/user_data.h b/components/autofill_assistant/browser/user_data.h index 582cc682..e3fc8f0 100644 --- a/components/autofill_assistant/browser/user_data.h +++ b/components/autofill_assistant/browser/user_data.h
@@ -52,12 +52,14 @@ // Represents a concrete login choice in the UI, e.g., 'Guest checkout' or // a particular Chrome PWM login account. struct LoginChoice { - LoginChoice(const std::string& id, - const std::string& label, - const std::string& sublabel, - const base::Optional<std::string>& sublabel_accessibility_hint, - int priority, - const base::Optional<InfoPopupProto>& info_popup); + LoginChoice( + const std::string& id, + const std::string& label, + const std::string& sublabel, + const base::Optional<std::string>& sublabel_accessibility_hint, + int priority, + const base::Optional<InfoPopupProto>& info_popup, + const base::Optional<std::string>& edit_button_content_description); LoginChoice(const LoginChoice& another); ~LoginChoice(); @@ -73,6 +75,8 @@ int preselect_priority = -1; // The popup to show to provide more information about this login choice. base::Optional<InfoPopupProto> info_popup; + // The a11y hint for the edit button. + base::Optional<std::string> edit_button_content_description; }; // Tuple for holding credit card and billing address;
diff --git a/components/autofill_assistant/browser/web/element.cc b/components/autofill_assistant/browser/web/element.cc index 716570f..b105044 100644 --- a/components/autofill_assistant/browser/web/element.cc +++ b/components/autofill_assistant/browser/web/element.cc
@@ -18,6 +18,9 @@ content::RenderFrameHost* FindCorrespondingRenderFrameHost( const std::string& frame_id, content::WebContents* web_contents) { + if (frame_id.empty()) { + return web_contents->GetMainFrame(); + } const auto& all_frames = web_contents->GetAllFrames(); const auto& it = std::find_if( all_frames.begin(), all_frames.end(), [&](const auto& frame) {
diff --git a/components/autofill_assistant/browser/web/element_store.h b/components/autofill_assistant/browser/web/element_store.h index f371cfac..665f8e1 100644 --- a/components/autofill_assistant/browser/web/element_store.h +++ b/components/autofill_assistant/browser/web/element_store.h
@@ -23,7 +23,7 @@ public: // |web_contents| must outlive this instance. ElementStore(content::WebContents* web_contents); - ~ElementStore(); + virtual ~ElementStore(); ElementStore(const ElementStore&) = delete; ElementStore& operator=(const ElementStore&) = delete; @@ -35,8 +35,8 @@ // Get an element from the store. If the element does not exist or cannot be // reconstructed this returns an error status. - ClientStatus GetElement(const std::string& client_id, - ElementFinder::Result* out_element) const; + virtual ClientStatus GetElement(const std::string& client_id, + ElementFinder::Result* out_element) const; // Removes an element. Returns true if the element was removed. bool RemoveElement(const std::string& client_id); @@ -48,6 +48,8 @@ void Clear(); private: + friend class FakeElementStore; + content::WebContents* web_contents_; base::flat_map<std::string, DomObjectFrameStack> object_map_;
diff --git a/components/autofill_assistant/browser/web/element_store_unittest.cc b/components/autofill_assistant/browser/web/element_store_unittest.cc index bcbbe079..23b61827 100644 --- a/components/autofill_assistant/browser/web/element_store_unittest.cc +++ b/components/autofill_assistant/browser/web/element_store_unittest.cc
@@ -71,6 +71,7 @@ TEST_F(ElementStoreTest, GetElementFromStoreWithBadFrameHost) { auto element = std::make_unique<ElementFinder::Result>(); element->dom_object.object_data.object_id = "1"; + element->dom_object.object_data.node_frame_id = "unknown"; AddElement("1", std::move(element)); ElementFinder::Result result; @@ -78,6 +79,17 @@ element_store_->GetElement("1", &result).proto_status()); } +TEST_F(ElementStoreTest, GetElementFromStoreWithNoFrameId) { + auto element = std::make_unique<ElementFinder::Result>(); + element->dom_object.object_data.object_id = "1"; + AddElement("1", std::move(element)); + + ElementFinder::Result result; + EXPECT_EQ(ACTION_APPLIED, + element_store_->GetElement("1", &result).proto_status()); + EXPECT_EQ(web_contents()->GetMainFrame(), result.container_frame_host); +} + TEST_F(ElementStoreTest, AddElementToStoreOverwrites) { auto element_1 = CreateElement("1"); auto element_2 = CreateElement("2");
diff --git a/components/autofill_assistant/browser/web/fake_element_store.cc b/components/autofill_assistant/browser/web/fake_element_store.cc new file mode 100644 index 0000000..bdfff4e --- /dev/null +++ b/components/autofill_assistant/browser/web/fake_element_store.cc
@@ -0,0 +1,26 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/web/fake_element_store.h" +#include "components/autofill_assistant/browser/client_status.h" + +namespace autofill_assistant { + +FakeElementStore::FakeElementStore() : ElementStore(nullptr) {} + +FakeElementStore::~FakeElementStore() = default; + +ClientStatus FakeElementStore::GetElement( + const std::string& client_id, + ElementFinder::Result* out_element) const { + auto it = object_map_.find(client_id); + if (it == object_map_.end()) { + return ClientStatus(CLIENT_ID_RESOLUTION_FAILED); + } + + out_element->dom_object = it->second; + return OkClientStatus(); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/fake_element_store.h b/components/autofill_assistant/browser/web/fake_element_store.h new file mode 100644 index 0000000..5e3a333 --- /dev/null +++ b/components/autofill_assistant/browser/web/fake_element_store.h
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_FAKE_ELEMENT_STORE_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_FAKE_ELEMENT_STORE_H_ + +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_finder.h" +#include "components/autofill_assistant/browser/web/element_store.h" + +namespace autofill_assistant { + +class FakeElementStore : public ElementStore { + public: + FakeElementStore(); + ~FakeElementStore() override; + + FakeElementStore(const FakeElementStore&) = delete; + FakeElementStore& operator=(const FakeElementStore&) = delete; + + ClientStatus GetElement(const std::string& client_id, + ElementFinder::Result* out_element) const override; +}; + +} // namespace autofill_assistant + +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_FAKE_ELEMENT_STORE_H_
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc index 74f1048..a3a025f3 100644 --- a/components/autofill_assistant/browser/web/web_controller.cc +++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -1155,10 +1155,19 @@ std::move(callback)))); } +void WebController::SendTextInput( + int key_press_delay_in_millisecond, + const std::string& value, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> callback) { + SendKeyboardInput(element, UTF8ToUnicode(value), + key_press_delay_in_millisecond, std::move(callback)); +} + void WebController::SendKeyboardInput( const ElementFinder::Result& element, const std::vector<UChar32>& codepoints, - const int delay_in_millisecond, + const int key_press_delay_in_millisecond, base::OnceCallback<void(const ClientStatus&)> callback) { if (VLOG_IS_ON(3)) { std::string input_str; @@ -1174,7 +1183,7 @@ DispatchKeyboardTextDownEvent( element.node_frame_id(), codepoints, 0, - /* delay= */ false, delay_in_millisecond, + /* delay= */ false, key_press_delay_in_millisecond, base::BindOnce(&DecorateWebControllerStatus, WebControllerErrorInfoProto::SEND_KEYBOARD_INPUT, std::move(callback)));
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h index 6af7e7f..1d1399d 100644 --- a/components/autofill_assistant/browser/web/web_controller.h +++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -198,14 +198,24 @@ const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback); - // Sets the keyboard focus to |element| and inputs |codepoints|, one - // character at a time. Key presses will have a delay of |delay_in_milli| - // between them. - // Returns the result through |callback|. + // Inputs the specified codepoints into |element|. Expects the |element| to + // have focus. Key presses will have a delay of + // |key_press_delay_in_millisecond| between them. Returns the result through + // |callback|. virtual void SendKeyboardInput( const ElementFinder::Result& element, const std::vector<UChar32>& codepoints, - int delay_in_milli, + int key_press_delay_in_millisecond, + base::OnceCallback<void(const ClientStatus&)> callback); + + // Inputs the specified |value| into |element| with keystrokes per character. + // Expects the |element| to have focus. Key presses will have a delay of + // |key_press_delay_in_millisecond| between them. Returns the result through + // |callback|. + virtual void SendTextInput( + int key_press_delay_in_millisecond, + const std::string& value, + const ElementFinder::Result& element, base::OnceCallback<void(const ClientStatus&)> callback); // Return the outerHTML of |element|.
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index 8977dbb3..3d0b368 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -185,8 +185,9 @@ std::unique_ptr<ElementFinder::Result> element_result) { EXPECT_EQ(ACTION_APPLIED, status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); PerformClickOrTap( - click_type, *element_result, + click_type, *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -267,8 +268,9 @@ } ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->ScrollToElementPosition( - *element_result, top_padding, + *element_result_ptr, top_padding, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -308,8 +310,9 @@ } ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->SelectOption( - *element_result, re2, case_sensitive, option_comparison_attribute, + *element_result_ptr, re2, case_sensitive, option_comparison_attribute, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -359,8 +362,9 @@ } ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->HighlightElement( - *element_result, + *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -391,8 +395,9 @@ std::unique_ptr<ElementFinder::Result> element_result) { EXPECT_EQ(ACTION_APPLIED, element_status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->GetOuterHtml( - *element_result, + *element_result_ptr, base::BindOnce( &WebControllerBrowserTest::ElementRetainingStringCallback, base::Unretained(this), std::move(element_result), @@ -421,11 +426,13 @@ EXPECT_EQ(ACTION_APPLIED, client_status.proto_status()); ASSERT_TRUE(elements); + const ElementFinder::Result* elements_ptr = elements.get(); web_controller_->GetOuterHtmls( - *elements, base::BindOnce(&WebControllerBrowserTest::OnGetOuterHtmls, - base::Unretained(this), std::move(elements), - std::move(done_callback), - client_status_output, htmls_output)); + *elements_ptr, + base::BindOnce(&WebControllerBrowserTest::OnGetOuterHtmls, + base::Unretained(this), std::move(elements), + std::move(done_callback), client_status_output, + htmls_output)); } void OnGetOuterHtmls(std::unique_ptr<ElementFinder::Result> elements, @@ -464,8 +471,9 @@ std::unique_ptr<ElementFinder::Result> element_result) { EXPECT_EQ(ACTION_APPLIED, element_status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->GetElementTag( - *element_result, + *element_result_ptr, base::BindOnce( &WebControllerBrowserTest::ElementRetainingStringCallback, base::Unretained(this), std::move(element_result), @@ -570,8 +578,9 @@ std::unique_ptr<ElementFinder::Result> element_result) { EXPECT_EQ(ACTION_APPLIED, element_status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->GetStringAttribute( - *element_result, attributes, + *element_result_ptr, attributes, base::BindOnce( &WebControllerBrowserTest::ElementRetainingStringCallback, base::Unretained(this), std::move(element_result), @@ -606,8 +615,9 @@ element_status, std::string()); return; } + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->GetFieldValue( - *element_result, + *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::OnGetFieldValue, base::Unretained(this), std::move(element_result), std::move(done_callback), @@ -659,8 +669,9 @@ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); PerformSetFieldValue( - value, fill_strategy, *element_result, + value, fill_strategy, *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -769,8 +780,9 @@ std::unique_ptr<ElementFinder::Result> element_result) { EXPECT_EQ(ACTION_APPLIED, element_status.proto_status()); ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); PerformSendKeyboardInput( - codepoints, delay_in_milli, use_js_focus, *element_result, + codepoints, delay_in_milli, use_js_focus, *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -846,8 +858,9 @@ } ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->SetAttribute( - *element_result, attributes, value, + *element_result_ptr, attributes, value, base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output)); @@ -880,8 +893,9 @@ } ASSERT_TRUE(element_result != nullptr); + const ElementFinder::Result* element_result_ptr = element_result.get(); web_controller_->GetElementRect( - *element_result, + *element_result_ptr, base::BindOnce(&WebControllerBrowserTest::OnGetElementRect, base::Unretained(this), std::move(element_result), std::move(done_callback), result_output, rect_output));
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java index 0cf0c1c..8051bdf 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -7,6 +7,7 @@ import static org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge.SITE_WILDCARD; import android.app.Activity; +import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -170,6 +171,8 @@ // Map from preference key to ContentSettingsType. private Map<String, Integer> mPreferenceMap; + private Dialog mConfirmationDialog; + private class SingleWebsitePermissionsPopulator implements WebsitePermissionsFetcher.WebsitePermissionsCallback { private final WebsiteAddress mSiteAddress; @@ -232,6 +235,14 @@ super.onActivityCreated(savedInstanceState); } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (mConfirmationDialog != null) { + mConfirmationDialog.dismiss(); + } + } + private void init() { Object extraSite = getArguments().getSerializable(EXTRA_SITE); Object extraSiteAddress = getArguments().getSerializable(EXTRA_SITE_ADDRESS); @@ -1044,6 +1055,10 @@ @Override public boolean onPreferenceChange(Preference preference, Object newValue) { + // It is possible that this UI is destroyed while a ListPreference dialog is open because + // incognito mode is closed through the system notification. + if (getView() == null) return true; + @ContentSettingValues int permission = ContentSetting.fromString((String) newValue); BrowserContextHandle browserContextHandle = @@ -1076,23 +1091,26 @@ : R.string.website_reset_confirmation; int buttonResId = mHideNonPermissionPreferences ? R.string.reset : titleResId; // Handle the Clear & Reset preference click by showing a confirmation. - new AlertDialog.Builder(getContext(), R.style.Theme_Chromium_AlertDialog) - .setTitle(titleResId) - .setMessage(confirmationResId) - .setPositiveButton(buttonResId, - (dialog, which) -> { - if (mHideNonPermissionPreferences) { - mSiteDataCleaner.resetPermissions( - getSiteSettingsClient().getBrowserContextHandle(), mSite); - } else { - resetSite(); - } - if (mWebsiteSettingsObserver != null) { - mWebsiteSettingsObserver.onPermissionsReset(); - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); + mConfirmationDialog = + new AlertDialog.Builder(getContext(), R.style.Theme_Chromium_AlertDialog) + .setTitle(titleResId) + .setMessage(confirmationResId) + .setPositiveButton(buttonResId, + (dialog, which) -> { + if (mHideNonPermissionPreferences) { + mSiteDataCleaner.resetPermissions( + getSiteSettingsClient().getBrowserContextHandle(), + mSite); + } else { + resetSite(); + } + if (mWebsiteSettingsObserver != null) { + mWebsiteSettingsObserver.onPermissionsReset(); + } + }) + .setNegativeButton( + R.string.cancel, (dialog, which) -> mConfirmationDialog = null) + .show(); return true; }
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc index e57704f..3a52635 100644 --- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc +++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/memory/unsafe_shared_memory_region.h" #include "base/path_service.h" +#include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" @@ -271,7 +272,8 @@ public: JpegClient(const std::vector<TestImage*>& test_aligned_images, const std::vector<TestImage*>& test_images, - media::test::ClientStateNotification<ClientState>* note); + media::test::ClientStateNotification<ClientState>* note, + size_t exif_size); ~JpegClient() override; void CreateJpegEncoder(); void DestroyJpegEncoder(); @@ -325,6 +327,10 @@ // this. media::test::ClientStateNotification<ClientState>* note_; + // EXIF data size for testing. + size_t exif_size_; + // Input buffer for EXIF data. + media::BitstreamBuffer exif_buffer_; // Output buffer prepared for JpegEncodeAccelerator. media::BitstreamBuffer encoded_buffer_; @@ -348,11 +354,13 @@ JpegClient::JpegClient(const std::vector<TestImage*>& test_aligned_images, const std::vector<TestImage*>& test_images, - media::test::ClientStateNotification<ClientState>* note) + media::test::ClientStateNotification<ClientState>* note, + size_t exif_size) : test_aligned_images_(test_aligned_images), test_unaligned_images_(test_images), state_(ClientState::CREATED), note_(note), + exif_size_(exif_size), gpu_memory_buffer_manager_(new media::LocalGpuMemoryBufferManager()) {} JpegClient::~JpegClient() {} @@ -547,6 +555,14 @@ void JpegClient::PrepareMemory(int32_t bitstream_buffer_id) { TestImage* test_image = GetTestImage(bitstream_buffer_id); + if (exif_size_ > 0) { + auto shm = base::UnsafeSharedMemoryRegion::Create(exif_size_); + auto shm_mapping = shm.Map(); + base::RandBytes(shm_mapping.memory(), exif_size_); + exif_buffer_ = + media::BitstreamBuffer(bitstream_buffer_id, std::move(shm), exif_size_); + } + size_t input_size = test_image->image_data.size(); if (!in_mapping_.IsValid() || input_size > in_mapping_.size()) { in_shm_ = base::UnsafeSharedMemoryRegion::Create(input_size); @@ -632,7 +648,8 @@ input_frame_->BackWithSharedMemory(&in_shm_); buffer_id_to_start_time_[bitstream_buffer_id] = base::TimeTicks::Now(); - encoder_->Encode(input_frame_, kJpegDefaultQuality, nullptr, + encoder_->Encode(input_frame_, kJpegDefaultQuality, + exif_size_ > 0 ? &exif_buffer_ : nullptr, std::move(encoded_buffer_)); } @@ -673,14 +690,17 @@ buffer_id_to_start_time_[bitstream_buffer_id] = base::TimeTicks::Now(); encoder_->EncodeWithDmaBuf(input_frame, hw_out_frame_, kJpegDefaultQuality, - bitstream_buffer_id, nullptr); + bitstream_buffer_id, + exif_size_ > 0 ? &exif_buffer_ : nullptr); } class JpegEncodeAcceleratorTest : public ::testing::Test { protected: JpegEncodeAcceleratorTest() {} - void TestEncode(size_t num_concurrent_encoders, bool is_dma); + void TestEncode(size_t num_concurrent_encoders, + bool is_dma, + size_t exif_size); // This is needed to allow the usage of methods in post_task.h in // JpegEncodeAccelerator implementations. @@ -696,7 +716,8 @@ }; void JpegEncodeAcceleratorTest::TestEncode(size_t num_concurrent_encoders, - bool is_dma) { + bool is_dma, + size_t exif_size) { base::Thread encoder_thread("EncoderThread"); ASSERT_TRUE(encoder_thread.Start()); @@ -710,7 +731,8 @@ notes.push_back( std::make_unique<media::test::ClientStateNotification<ClientState>>()); clients.push_back(std::make_unique<JpegClient>( - test_aligned_images_, test_unaligned_images_, notes.back().get())); + test_aligned_images_, test_unaligned_images_, notes.back().get(), + exif_size)); encoder_thread.task_runner()->PostTask( FROM_HERE, base::BindOnce(&JpegClient::CreateJpegEncoder, base::Unretained(clients.back().get()))); @@ -801,32 +823,37 @@ test_aligned_images_.push_back(image.get()); } } - TestEncode(1, false); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/false, + /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, MultipleEncoders) { for (auto& image : g_env->image_data_user_) { test_aligned_images_.push_back(image.get()); } - TestEncode(3, false); + TestEncode(/*num_concurrent_encoders=*/3u, /*is_dma=*/false, + /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, ResolutionChange) { test_aligned_images_.push_back(g_env->image_data_640x368_black_.get()); test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get()); - TestEncode(1, false); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/false, + /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, AlignedSizes) { test_aligned_images_.push_back(g_env->image_data_2560x1920_white_.get()); test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get()); test_aligned_images_.push_back(g_env->image_data_640x480_black_.get()); - TestEncode(1, false); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/false, + /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignment) { test_unaligned_images_.push_back(g_env->image_data_640x360_black_.get()); - TestEncode(1, false); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/false, + /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, SimpleDmaEncode) { @@ -835,32 +862,49 @@ test_aligned_images_.push_back(image.get()); } } - TestEncode(1, true); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/true, /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, MultipleDmaEncoders) { for (auto& image : g_env->image_data_user_) { test_aligned_images_.push_back(image.get()); } - TestEncode(3, true); + TestEncode(/*num_concurrent_encoders=*/3u, /*is_dma=*/true, /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, ResolutionChangeDma) { test_aligned_images_.push_back(g_env->image_data_640x368_black_.get()); test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get()); - TestEncode(1, true); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/true, /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, AlignedSizesDma) { test_aligned_images_.push_back(g_env->image_data_2560x1920_white_.get()); test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get()); test_aligned_images_.push_back(g_env->image_data_640x480_black_.get()); - TestEncode(1, true); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/true, /*exif_size=*/0u); } TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignmentDma) { test_unaligned_images_.push_back(g_env->image_data_640x360_black_.get()); - TestEncode(1, true); + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/true, /*exif_size=*/0u); +} + +TEST_F(JpegEncodeAcceleratorTest, ExifSizesDma) { + for (size_t i = 0; i < g_env->repeat_; i++) { + for (auto& image : g_env->image_data_user_) { + test_aligned_images_.push_back(image.get()); + } + } + // Intel iHD driver is known to fail when |exif_size| % 1020 == 411, so we + // sample more around these numbers. + constexpr size_t kTestExifSizes[] = { + 8000u, 8571u, 9000u, 9591u, 10000u, + 10609u, 10610u, 10611u, 10612u, 11111u, + }; + for (size_t exif_size : kTestExifSizes) { + TestEncode(/*num_concurrent_encoders=*/1u, /*is_dma=*/true, exif_size); + } } } // namespace
diff --git a/components/crash/content/browser/BUILD.gn b/components/crash/content/browser/BUILD.gn index 7649900..af6c561 100644 --- a/components/crash/content/browser/BUILD.gn +++ b/components/crash/content/browser/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") + if (is_android) { import("//build/config/android/config.gni") } @@ -25,9 +27,11 @@ "crash_handler_host_linux.cc", "crash_handler_host_linux.h", ] + + deps += [ "//build:chromeos_buildflags" ] } - if (!is_chromeos) { + if (!is_chromeos_ash) { deps += [ "//third_party/crashpad/crashpad/client" ] }
diff --git a/components/crash/content/browser/crash_handler_host_linux.h b/components/crash/content/browser/crash_handler_host_linux.h index b40c795c..7728a1f 100644 --- a/components/crash/content/browser/crash_handler_host_linux.h +++ b/components/crash/content/browser/crash_handler_host_linux.h
@@ -20,6 +20,7 @@ #include "base/synchronization/lock.h" #include "base/task/current_thread.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #if !defined(OS_ANDROID) #include "components/crash/core/app/breakpad_linux_impl.h" @@ -119,7 +120,7 @@ #endif // !defined(OS_ANDROID) -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) namespace crashpad { @@ -178,6 +179,6 @@ } // namespace crashpad -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #endif // COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_HANDLER_HOST_LINUX_H_
diff --git a/components/crash/core/app/BUILD.gn b/components/crash/core/app/BUILD.gn index 4eb4173..6176836 100644 --- a/components/crash/core/app/BUILD.gn +++ b/components/crash/core/app/BUILD.gn
@@ -70,6 +70,7 @@ deps = [ "//base", "//build:branding_buildflags", + "//build:chromeos_buildflags", "//content/public/common:content_descriptors", ] @@ -152,6 +153,7 @@ deps = [ "//base", + "//build:chromeos_buildflags", "//components/browser_watcher:activity_report", "//components/gwp_asan/buildflags", "//third_party/crashpad/crashpad/client",
diff --git a/components/crash/core/app/breakpad_linux.cc b/components/crash/core/app/breakpad_linux.cc index 9d8370e..9e850c0 100644 --- a/components/crash/core/app/breakpad_linux.cc +++ b/components/crash/core/app/breakpad_linux.cc
@@ -61,9 +61,10 @@ #include "base/android/path_utils.h" #include "base/debug/leak_annotations.h" #endif +#include "build/chromeos_buildflags.h" #include "third_party/lss/linux_syscall_support.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "components/crash/core/app/crash_switches.h" #endif @@ -93,7 +94,7 @@ namespace { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // An optional UNIX timestamp passed to us from session_manager. If set, // session_manager thinks we are in a possible crash-loop and will log the user // out if we crash again before the indicated time. We don't actually do much @@ -244,7 +245,7 @@ output[index - 1] = '0' + (i % 10); } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) bool my_isxdigit(char c) { return base::IsAsciiDigit(c) || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); } @@ -291,7 +292,7 @@ } // MIME substrings. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) const char g_sep[] = ":"; #endif const char g_rn[] = "\r\n"; @@ -471,7 +472,7 @@ size)); } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // This subclass is used on Chromium OS to report crashes in a format easy for // the central crash reporting facility to understand. // Format is <name>:<data length in decimal>:<data> @@ -584,7 +585,7 @@ AddItem(file_data, file_size); Flush(); } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_ANDROID) // Writes the "package" field, which is in the format: @@ -1141,7 +1142,7 @@ void SetCrashLoopBeforeTime(const std::string& process_type, const base::CommandLine& parsed_command_line) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) std::string crash_loop_before = parsed_command_line.GetSwitchValueASCII( crash_reporter::switches::kCrashLoopBefore); if (crash_loop_before.empty()) { @@ -1153,7 +1154,7 @@ << crash_loop_before << " to integer"; g_crash_loop_before_time = 0; } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } // Miscellaneous initialization functions to call after Breakpad has been @@ -1262,7 +1263,7 @@ const char* exe_buf, int upload_status_fd, google_breakpad::PageAllocator* allocator) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // CrOS uses crash_reporter instead of wget to report crashes, // it needs to know where the crash dump lives and the pid and uid of the // crashing process. @@ -1311,7 +1312,7 @@ static const char msg[] = "Cannot upload crash dump: cannot exec " "/sbin/crash_reporter\n"; -#else // defined(OS_CHROMEOS) +#else // BUILDFLAG(IS_CHROMEOS_ASH) // Compress |dumpfile| with gzip. const pid_t gzip_child = sys_fork(); @@ -1401,7 +1402,7 @@ }; static const char msg[] = "Cannot upload crash dump: cannot exec " "/usr/bin/wget\n"; -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) execve(args[0], const_cast<char**>(args), environ); WriteLog(msg, sizeof(msg) - 1); @@ -1452,7 +1453,7 @@ WriteLog(msg, sizeof(msg) - 1); return false; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // See kSuccessMagic in platform2/crash-reporter/chrome_collector.cc. return my_strcmp(buf, "_sys_cr_finished") == 0; #else @@ -1469,7 +1470,7 @@ size_t expected_len) { WriteNewline(); if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) static const char msg[] = "System crash_reporter failed to process crash report."; #else @@ -1485,7 +1486,7 @@ return; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) static const char msg[] = "Crash dump received by crash_reporter\n"; WriteLog(msg, sizeof(msg) - 1); #else @@ -1516,7 +1517,7 @@ #endif } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) const char* GetCrashingProcessName(const BreakpadInfo& info, google_breakpad::PageAllocator* allocator) { // Symlink to process binary is at /proc/###/exe. @@ -1544,7 +1545,7 @@ // Either way too long, or a read error. return "chrome-crash-unknown-process"; } -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) // Attempts to close all open file descriptors other than stdin, stdout and // stderr (0, 1, and 2). @@ -1579,7 +1580,7 @@ return; } -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Grab the crashing process' name now, when it should still be available. // If we try to do this later in our grandchild the crashing process has // already terminated. @@ -1720,7 +1721,7 @@ // <dump contents> // \r\n BOUNDARY -- \r\n -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) CrashReporterWriter writer(temp_file_fd); #else MimeWriter writer(temp_file_fd, mime_boundary); @@ -2023,7 +2024,7 @@ #endif process_type.empty(); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) SetUploadURL(GetCrashReporterClient()->GetUploadUrl()); #endif
diff --git a/components/crash/core/app/crash_switches.cc b/components/crash/core/app/crash_switches.cc index d221ff6..dfcb6bd 100644 --- a/components/crash/core/app/crash_switches.cc +++ b/components/crash/core/app/crash_switches.cc
@@ -4,6 +4,8 @@ #include "components/crash/core/app/crash_switches.h" +#include "build/chromeos_buildflags.h" + namespace crash_reporter { namespace switches { @@ -20,7 +22,7 @@ const char kCrashpadHandlerPid[] = "crashpad-handler-pid"; #endif -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // A time_t. Passed by session_manager into the Chrome user session, indicating // that if Chrome crashes before the indicated time, session_manager will // consider this to be a crash-loop situation and log the user out. Chrome
diff --git a/components/crash/core/app/crash_switches.h b/components/crash/core/app/crash_switches.h index c989fb1..1855b80 100644 --- a/components/crash/core/app/crash_switches.h +++ b/components/crash/core/app/crash_switches.h
@@ -6,6 +6,7 @@ #define COMPONENTS_CRASH_CORE_APP_CRASH_SWITCHES_H_ #include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace crash_reporter { namespace switches { @@ -16,7 +17,7 @@ extern const char kCrashpadHandlerPid[]; #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) extern const char kCrashLoopBefore[]; #endif
diff --git a/components/crash/core/app/crashpad.cc b/components/crash/core/app/crashpad.cc index e1c66df..64ca383 100644 --- a/components/crash/core/app/crashpad.cc +++ b/components/crash/core/app/crashpad.cc
@@ -27,6 +27,7 @@ #include "base/system/sys_info.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/crash/core/app/crash_reporter_client.h" #include "third_party/crashpad/crashpad/client/annotation.h" #include "third_party/crashpad/crashpad/client/annotation_list.h" @@ -200,7 +201,7 @@ g_database = crashpad::CrashReportDatabase::Initialize(database_path).release(); -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); SetUploadConsent(crash_reporter_client->GetCollectStatsConsent()); #endif @@ -240,7 +241,7 @@ return *client; } -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) void SetUploadConsent(bool consent) { if (!g_database) return; @@ -272,7 +273,7 @@ return false; } -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) #if !defined(OS_ANDROID) void DumpWithoutCrashing() {
diff --git a/components/crash/core/app/crashpad.h b/components/crash/core/app/crashpad.h index 15c16b3..f661a154 100644 --- a/components/crash/core/app/crashpad.h +++ b/components/crash/core/app/crashpad.h
@@ -13,6 +13,7 @@ #include "base/files/file_path.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #if defined(OS_APPLE) #include "base/mac/scoped_mach_port.h" @@ -107,7 +108,7 @@ // ChromeOS has its own, OS-level consent system; Chrome does not maintain a // separate Upload Consent on ChromeOS. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) // Enables or disables crash report upload, taking the given consent to upload // into account. Consent may be ignored, uploads may not be enabled even with @@ -122,7 +123,7 @@ // Determines whether uploads are enabled or disabled. This information is only // available in the browser process. bool GetUploadsEnabled(); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) enum class ReportUploadState { NotUploaded,
diff --git a/components/crash/core/app/crashpad_linux.cc b/components/crash/core/app/crashpad_linux.cc index 2c9f505..8e020bf 100644 --- a/components/crash/core/app/crashpad_linux.cc +++ b/components/crash/core/app/crashpad_linux.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "build/branding_buildflags.h" +#include "build/chromeos_buildflags.h" #include "components/crash/core/app/crash_reporter_client.h" #include "components/crash/core/app/crash_switches.h" #include "content/public/common/content_descriptors.h" @@ -89,7 +90,7 @@ DCHECK(exe_path.empty()); crashpad::CrashpadClient client; -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) std::string crash_loop_before = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kCrashLoopBefore); @@ -120,7 +121,7 @@ // to ChromeOS's /sbin/crash_reporter which in turn passes the dump to // crash_sender which handles the upload. std::string url; -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) url = crash_reporter_client->GetUploadUrl(); #else url = std::string(); @@ -156,7 +157,7 @@ // contain these annotations. arguments.push_back("--monitor-self-annotation=ptype=crashpad-handler"); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) arguments.push_back("--use-cros-crash-reporter"); if (crash_reporter_client->IsRunningUnattended()) {
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn index 430910e..9acb9dc 100644 --- a/components/enterprise/BUILD.gn +++ b/components/enterprise/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") + static_library("enterprise") { sources = [ "browser/controller/browser_dm_token_storage.cc", @@ -16,6 +18,7 @@ deps = [ "//base", + "//build:chromeos_buildflags", "//components/policy/core/common", "//components/prefs", "//services/network/public/cpp", @@ -52,7 +55,7 @@ ] } - if (!is_android && !is_chromeos) { + if (!is_android && !is_chromeos_ash) { sources += [ "browser/controller/chrome_browser_cloud_management_controller.cc", "browser/controller/chrome_browser_cloud_management_controller.h", @@ -89,6 +92,9 @@ if (!is_android) { sources += [ "browser/reporting/report_uploader_unittest.cc" ] - deps += [ "//components/policy/core/common:test_support" ] + deps += [ + "//build:chromeos_buildflags", + "//components/policy/core/common:test_support", + ] } }
diff --git a/components/enterprise/browser/enterprise_switches.cc b/components/enterprise/browser/enterprise_switches.cc index 17046ca..d7787a1 100644 --- a/components/enterprise/browser/enterprise_switches.cc +++ b/components/enterprise/browser/enterprise_switches.cc
@@ -5,10 +5,11 @@ #include "components/enterprise/browser/enterprise_switches.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace switches { -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) // Enables the Chrome Browser Cloud Management integration on Chromium builds. // CBCM is always enabled in branded builds. const char kEnableChromeBrowserCloudManagement[] =
diff --git a/components/enterprise/browser/enterprise_switches.h b/components/enterprise/browser/enterprise_switches.h index 2a9b434..902e1f2 100644 --- a/components/enterprise/browser/enterprise_switches.h +++ b/components/enterprise/browser/enterprise_switches.h
@@ -9,10 +9,11 @@ #define COMPONENTS_ENTERPRISE_BROWSER_ENTERPRISE_SWITCHES_H_ #include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace switches { -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) extern const char kEnableChromeBrowserCloudManagement[]; #endif
diff --git a/components/enterprise/browser/reporting/browser_report_generator.cc b/components/enterprise/browser/reporting/browser_report_generator.cc index e16dda6..67a02cc 100644 --- a/components/enterprise/browser/reporting/browser_report_generator.cc +++ b/components/enterprise/browser/reporting/browser_report_generator.cc
@@ -9,6 +9,7 @@ #include "base/version.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/enterprise/browser/reporting/reporting_delegate_factory.h" #include "components/policy/core/common/cloud/cloud_policy_util.h" #include "components/version_info/version_info.h" @@ -40,7 +41,7 @@ } void BrowserReportGenerator::GenerateBasicInfo(em::BrowserReport* report) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) report->set_browser_version(version_info::GetVersionNumber()); report->set_channel(policy::ConvertToProtoChannel(delegate_->GetChannel())); delegate_->GenerateBuildStateInfo(report);
diff --git a/components/enterprise/browser/reporting/policy_info.cc b/components/enterprise/browser/reporting/policy_info.cc index 580b525a..5727814 100644 --- a/components/enterprise/browser/reporting/policy_info.cc +++ b/components/enterprise/browser/reporting/policy_info.cc
@@ -8,6 +8,7 @@ #include "base/json/json_writer.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/policy/core/browser/policy_conversions.h" #include "components/policy/core/common/cloud/cloud_policy_client.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" @@ -135,7 +136,7 @@ void AppendMachineLevelUserCloudPolicyFetchTimestamp( em::ChromeUserProfileInfo* profile_info, policy::MachineLevelUserCloudPolicyManager* manager) { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (!manager || !manager->IsClientRegistered()) return; auto* timestamp = profile_info->add_policy_fetched_timestamps(); @@ -143,7 +144,7 @@ policy::dm_protocol::kChromeMachineLevelExtensionCloudPolicyType); timestamp->set_timestamp( manager->core()->client()->last_policy_timestamp().ToJavaTime()); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) } } // namespace enterprise_reporting
diff --git a/components/enterprise/browser/reporting/profile_report_generator.cc b/components/enterprise/browser/reporting/profile_report_generator.cc index 0e641ea..4488f9a 100644 --- a/components/enterprise/browser/reporting/profile_report_generator.cc +++ b/components/enterprise/browser/reporting/profile_report_generator.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/files/file_path.h" +#include "build/chromeos_buildflags.h" #include "components/enterprise/browser/reporting/policy_info.h" #include "components/enterprise/browser/reporting/reporting_delegate_factory.h" #include "components/policy/core/browser/policy_conversions.h" @@ -43,11 +44,11 @@ if (report_type == ReportType::kExtensionRequest) { delegate_->GetExtensionRequest(report_.get()); report_->set_is_detail_available(true); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Extension request is aggregated at the user level on CrOS. report_->set_name(name); delegate_->GetSigninUserInfo(report_.get()); -#endif // defined(OS_CHROMEOS) +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } else { report_->set_name(name); report_->set_is_detail_available(true); @@ -83,10 +84,10 @@ } void ProfileReportGenerator::GetPolicyFetchTimestampInfo() { -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) AppendMachineLevelUserCloudPolicyFetchTimestamp( report_.get(), delegate_->GetCloudPolicyManager()); -#endif // !defined(OS_CHROMEOS) +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) } } // namespace enterprise_reporting
diff --git a/components/enterprise/browser/reporting/report_generator.cc b/components/enterprise/browser/reporting/report_generator.cc index a881a05..ab701ab 100644 --- a/components/enterprise/browser/reporting/report_generator.cc +++ b/components/enterprise/browser/reporting/report_generator.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/enterprise/browser/reporting/browser_report_generator.h" #include "components/enterprise/browser/reporting/reporting_delegate_factory.h" #include "components/policy/core/common/cloud/cloud_policy_util.h" @@ -46,7 +47,7 @@ basic_request->add_partial_report_types( em::PartialReportType::EXTENSION_REQUEST); } else { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) delegate_->SetAndroidAppInfos(basic_request.get()); #else basic_request->set_computer_name(this->GetMachineName());
diff --git a/components/enterprise/browser/reporting/report_request_definition.h b/components/enterprise/browser/reporting/report_request_definition.h index 5fdcc22..0775104 100644 --- a/components/enterprise/browser/reporting/report_request_definition.h +++ b/components/enterprise/browser/reporting/report_request_definition.h
@@ -6,6 +6,7 @@ #define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_DEFINITION_H_ #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/policy/proto/device_management_backend.pb.h" namespace enterprise_reporting { @@ -16,7 +17,7 @@ // upload usage data to DM Server. By the reference to this macro, most classes // in enterprise_reporting namespace can share the same logic for various // operation systems. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) using ReportRequest = enterprise_management::ChromeOsUserReportRequest; #else using ReportRequest = enterprise_management::ChromeDesktopReportRequest;
diff --git a/components/enterprise/browser/reporting/report_request_queue_generator.cc b/components/enterprise/browser/reporting/report_request_queue_generator.cc index a719a505..3614627 100644 --- a/components/enterprise/browser/reporting/report_request_queue_generator.cc +++ b/components/enterprise/browser/reporting/report_request_queue_generator.cc
@@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "base/metrics/histogram_functions.h" +#include "build/chromeos_buildflags.h" namespace enterprise_reporting { @@ -35,7 +36,7 @@ ReportingDelegateFactory* delegate_factory) : maximum_report_size_(kMaximumReportSize), profile_report_generator_(delegate_factory) { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // For Chrome OS, policy information needn't be uploaded to DM server. profile_report_generator_.set_policies_enabled(false); #endif
diff --git a/components/enterprise/browser/reporting/report_scheduler.cc b/components/enterprise/browser/reporting/report_scheduler.cc index 63dbdd9..214b27e 100644 --- a/components/enterprise/browser/reporting/report_scheduler.cc +++ b/components/enterprise/browser/reporting/report_scheduler.cc
@@ -13,6 +13,7 @@ #include "base/task/post_task.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/enterprise/browser/controller/browser_dm_token_storage.h" #include "components/enterprise/browser/reporting/common_pref_names.h" #include "components/enterprise/browser/reporting/reporting_delegate_factory.h" @@ -124,7 +125,7 @@ // For Chrome OS, it needn't register the cloud policy client here. The // |dm_token| and |client_id| should have already existed after the client is // initialized, and will keep valid during whole life-cycle. -#if !defined(OS_CHROMEOS) +#if !BUILDFLAG(IS_CHROMEOS_ASH) if (!SetupBrowserPolicyClientRegistration()) { Stop(); return;
diff --git a/components/enterprise/browser/reporting/report_uploader.cc b/components/enterprise/browser/reporting/report_uploader.cc index 85fef3d..1f0e0fb 100644 --- a/components/enterprise/browser/reporting/report_uploader.cc +++ b/components/enterprise/browser/reporting/report_uploader.cc
@@ -8,6 +8,7 @@ #include "base/metrics/histogram_functions.h" #include "base/time/time.h" +#include "build/chromeos_buildflags.h" #include "components/policy/core/common/cloud/cloud_policy_client.h" namespace em = enterprise_management; @@ -51,7 +52,7 @@ auto callback = base::BindRepeating(&ReportUploader::OnRequestFinished, weak_ptr_factory_.GetWeakPtr()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) client_->UploadChromeOsUserReport(std::move(request), std::move(callback)); #else client_->UploadChromeDesktopReport(std::move(request), std::move(callback));
diff --git a/components/enterprise/browser/reporting/report_uploader_unittest.cc b/components/enterprise/browser/reporting/report_uploader_unittest.cc index 2c55f149..c144a10 100644 --- a/components/enterprise/browser/reporting/report_uploader_unittest.cc +++ b/components/enterprise/browser/reporting/report_uploader_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,7 +34,7 @@ // Different CloudPolicyClient proxy function will be used in test cases based // on the current operation system. They share same retry and error handling // behaviors provided by ReportUploader. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #define UploadReportProxy UploadChromeOsUserReportProxy #else #define UploadReportProxy UploadChromeDesktopReportProxy
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java index 3e69919e..ba8390b2 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateClient.java
@@ -6,6 +6,7 @@ import android.app.Activity; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult; import org.chromium.components.navigation_interception.NavigationParams; import org.chromium.content_public.browser.WebContents; @@ -54,4 +55,10 @@ /* Invoked when a navigation has begun in the InterceptNavigationDelegateImpl instance * associated with this instance. */ void onNavigationStarted(NavigationParams params); + + /* Invoked when the InterceptNavigationDelegateImpl instance + * associated with this instance has reached a decision for the navigation specified by + * |params|. |overrideUrlLoadingResult| specifies the decision. */ + void onDecisionReachedForNavigation( + NavigationParams params, OverrideUrlLoadingResult overrideUrlLoadingResult); }
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java index 817f638..b36ce00 100644 --- a/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java +++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/InterceptNavigationDelegateImpl.java
@@ -10,6 +10,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; import org.chromium.base.task.PostTask; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult; import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResultType; import org.chromium.components.navigation_interception.InterceptNavigationDelegate; import org.chromium.components.navigation_interception.NavigationParams; @@ -131,11 +132,12 @@ ExternalNavigationParams params = buildExternalNavigationParams(navigationParams, redirectHandler, shouldCloseTab) .build(); - @OverrideUrlLoadingResultType - int result = mExternalNavHandler.shouldOverrideUrlLoading(params).getResultType(); - mLastOverrideUrlLoadingResultType = result; + OverrideUrlLoadingResult result = mExternalNavHandler.shouldOverrideUrlLoading(params); + mLastOverrideUrlLoadingResultType = result.getResultType(); - switch (result) { + mClient.onDecisionReachedForNavigation(navigationParams, result); + + switch (mLastOverrideUrlLoadingResultType) { case OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT: assert mExternalNavHandler.canExternalAppHandleUrl(url); if (navigationParams.isMainFrame) {
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index cbc77b4..d5c9bd8e 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//testing/test.gni") if (is_android) { @@ -127,7 +128,7 @@ "//url", ] - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ ":serialization" ] } @@ -477,7 +478,7 @@ deps += [ ":serialization" ] } - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ "//chromeos/dbus:test_support", "//chromeos/network:test_support",
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index ed6b3db..245eb18 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -210,11 +210,11 @@ #endif metrics::SystemProfileProto::OS* os = system_profile->mutable_os(); -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) // The Lacros browser runs on Chrome OS, but reports a special OS name to // differentiate itself from the built-in ash browser + window manager binary. os->set_name("Lacros"); -#elif defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_CHROMEOS_ASH) os->set_name("CrOS"); #else os->set_name(base::SysInfo::OperatingSystemName()); @@ -223,9 +223,9 @@ // On ChromeOS, KernelVersion refers to the Linux kernel version and // OperatingSystemVersion refers to the ChromeOS release version. -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) os->set_kernel_version(base::SysInfo::KernelVersion()); -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) // Linux operating system version is copied over into kernel version to be // consistent. os->set_kernel_version(base::SysInfo::OperatingSystemVersion());
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc index ac659478..9a3d1145 100644 --- a/components/metrics/metrics_log_unittest.cc +++ b/components/metrics/metrics_log_unittest.cc
@@ -77,7 +77,7 @@ // Returns the expected hardware class for a metrics log. std::string GetExpectedHardwareClass() { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) // Currently, we are relying on base/ implementation for functionality on our // side which can be fragile if in the future someone decides to change that. // This replicates the logic to get the hardware class for ChromeOS and this @@ -187,19 +187,19 @@ hardware->set_dll_base(reinterpret_cast<uint64_t>(CURRENT_MODULE())); #endif -#if BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_LACROS) system_profile->mutable_os()->set_name("Lacros"); -#elif defined(OS_CHROMEOS) +#elif BUILDFLAG(IS_CHROMEOS_ASH) system_profile->mutable_os()->set_name("CrOS"); #else system_profile->mutable_os()->set_name(base::SysInfo::OperatingSystemName()); #endif system_profile->mutable_os()->set_version( base::SysInfo::OperatingSystemVersion()); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) system_profile->mutable_os()->set_kernel_version( base::SysInfo::KernelVersion()); -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) system_profile->mutable_os()->set_kernel_version( base::SysInfo::OperatingSystemVersion()); #elif defined(OS_ANDROID)
diff --git a/components/metrics/net/network_metrics_provider_unittest.cc b/components/metrics/net/network_metrics_provider_unittest.cc index a25ed76f..e462bee 100644 --- a/components/metrics/net/network_metrics_provider_unittest.cc +++ b/components/metrics/net/network_metrics_provider_unittest.cc
@@ -12,14 +12,15 @@ #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "services/network/test/test_network_connection_tracker.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/metrics_proto/system_profile.pb.h" -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/network_handler.h" -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) #if defined(OS_IOS) #include "ios/web/public/test/web_task_environment.h" @@ -39,17 +40,17 @@ ~NetworkMetricsProviderTest() override {} void SetUp() override { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::DBusThreadManager::Initialize(); chromeos::NetworkHandler::Initialize(); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } void TearDown() override { -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) chromeos::NetworkHandler::Shutdown(); chromeos::DBusThreadManager::Shutdown(); -#endif // OS_CHROMEOS +#endif // BUILDFLAG(IS_CHROMEOS_ASH) } private:
diff --git a/components/metrics/persistent_histograms.cc b/components/metrics/persistent_histograms.cc index 7d2cc36..7ea2a0f 100644 --- a/components/metrics/persistent_histograms.cc +++ b/components/metrics/persistent_histograms.cc
@@ -18,6 +18,7 @@ #include "base/task/thread_pool.h" #include "base/time/time.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/metrics/persistent_system_profile.h" #include "components/variations/variations_associated_data.h" @@ -130,7 +131,9 @@ static const char kMappedFile[] = "MappedFile"; static const char kLocalMemory[] = "LocalMemory"; -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch +// of lacros-chrome is complete. +#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) // Linux kernel 4.4.0.* shows a huge number of SIGBUS crashes with persistent // histograms enabled using a mapped file. Change this to use local memory. // https://bugs.chromium.org/p/chromium/issues/detail?id=753741
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc index 5ea06444..0c39ac9 100644 --- a/components/metrics/stability_metrics_helper.cc +++ b/components/metrics/stability_metrics_helper.cc
@@ -27,7 +27,7 @@ #include <windows.h> // Needed for STATUS_* codes #endif -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #include "components/metrics/system_memory_stats_recorder.h" #endif @@ -250,7 +250,7 @@ // TODO(wfh): Check if this should be a Kill or a Crash on Android. break; #endif -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM: RecordChildKills(histogram_type); base::UmaHistogramExactLinear("BrowserRenderProcessHost.ChildKills.OOM",
diff --git a/components/metrics/system_memory_stats_recorder_linux.cc b/components/metrics/system_memory_stats_recorder_linux.cc index 1d46bc70..b15a05e 100644 --- a/components/metrics/system_memory_stats_recorder_linux.cc +++ b/components/metrics/system_memory_stats_recorder_linux.cc
@@ -31,7 +31,7 @@ UMA_HISTOGRAM_LINEAR(name, sample, 2500, 50) void RecordMemoryStats(RecordMemoryStatsType type) { -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) // Record graphics GEM object size in a histogram with 50 MB buckets. int mem_gpu_mb = 0; bool mem_gpu_result = false; @@ -58,7 +58,7 @@ // On Intel, graphics objects are in anonymous pages, but on ARM they are // not. For a total "allocated count" add in graphics pages on ARM. int mem_allocated_mb = (memory.active_anon + memory.inactive_anon) / 1024; -#if (defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)) && \ +#if (BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \ defined(ARCH_CPU_ARM_FAMILY) mem_allocated_mb += mem_gpu_mb; #endif @@ -83,7 +83,7 @@ } } -#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS) +#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) // Record shared memory (used by renderer/GPU buffers). int mem_shmem_mb = memory.shmem / 1024; switch (type) {
diff --git a/components/navigation_interception/android/java/src/org/chromium/components/navigation_interception/NavigationParams.java b/components/navigation_interception/android/java/src/org/chromium/components/navigation_interception/NavigationParams.java index e02aa54..14dac2c 100644 --- a/components/navigation_interception/android/java/src/org/chromium/components/navigation_interception/NavigationParams.java +++ b/components/navigation_interception/android/java/src/org/chromium/components/navigation_interception/NavigationParams.java
@@ -21,6 +21,12 @@ /** The referrer URL for the navigation. */ public final String referrer; + /** + * The ID of the C++-side NavigationHandle that this instance corresponds to, or 0 if + * this instance was not constructed from a NavigationHandle. + */ + public final long navigationId; + /** True if the the navigation method is "POST". */ public final boolean isPost; @@ -51,12 +57,13 @@ /** Initiator origin of the request, could be null. */ public final Origin initiatorOrigin; - public NavigationParams(String url, String referrer, boolean isPost, boolean hasUserGesture, - int pageTransitionType, boolean isRedirect, boolean isExternalProtocol, - boolean isMainFrame, boolean isRendererInitiated, boolean hasUserGestureCarryover, - @Nullable Origin initiatorOrigin) { + public NavigationParams(String url, String referrer, long navigationId, boolean isPost, + boolean hasUserGesture, int pageTransitionType, boolean isRedirect, + boolean isExternalProtocol, boolean isMainFrame, boolean isRendererInitiated, + boolean hasUserGestureCarryover, @Nullable Origin initiatorOrigin) { this.url = url; this.referrer = TextUtils.isEmpty(referrer) ? null : referrer; + this.navigationId = navigationId; this.isPost = isPost; this.hasUserGesture = hasUserGesture; this.pageTransitionType = pageTransitionType; @@ -69,12 +76,12 @@ } @CalledByNative - public static NavigationParams create(String url, String referrer, boolean isPost, - boolean hasUserGesture, int pageTransitionType, boolean isRedirect, + public static NavigationParams create(String url, String referrer, long navigationId, + boolean isPost, boolean hasUserGesture, int pageTransitionType, boolean isRedirect, boolean isExternalProtocol, boolean isMainFrame, boolean isRendererInitiated, boolean hasUserGestureCarryover, @Nullable Origin initiatorOrigin) { - return new NavigationParams(url, referrer, isPost, hasUserGesture, pageTransitionType, - isRedirect, isExternalProtocol, isMainFrame, isRendererInitiated, - hasUserGestureCarryover, initiatorOrigin); + return new NavigationParams(url, referrer, navigationId, isPost, hasUserGesture, + pageTransitionType, isRedirect, isExternalProtocol, isMainFrame, + isRendererInitiated, hasUserGestureCarryover, initiatorOrigin); } }
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc index 3953e16..44cbcab4 100644 --- a/components/navigation_interception/intercept_navigation_throttle.cc +++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -117,6 +117,7 @@ bool is_redirect) const { return NavigationParams(navigation_handle()->GetURL(), content::Referrer(navigation_handle()->GetReferrer()), + navigation_handle()->GetNavigationId(), navigation_handle()->HasUserGesture(), navigation_handle()->IsPost(), navigation_handle()->GetPageTransition(), is_redirect,
diff --git a/components/navigation_interception/navigation_params.cc b/components/navigation_interception/navigation_params.cc index de7a3f2..fb3d766 100644 --- a/components/navigation_interception/navigation_params.cc +++ b/components/navigation_interception/navigation_params.cc
@@ -9,6 +9,7 @@ NavigationParams::NavigationParams( const GURL& url, const content::Referrer& referrer, + int64_t navigation_id, bool has_user_gesture, bool is_post, ui::PageTransition transition_type, @@ -20,6 +21,7 @@ const base::Optional<url::Origin>& initiator_origin) : url_(url), referrer_(referrer), + navigation_id_(navigation_id), has_user_gesture_(has_user_gesture), is_post_(is_post), transition_type_(transition_type),
diff --git a/components/navigation_interception/navigation_params.h b/components/navigation_interception/navigation_params.h index bbd5fa0..bd6ae63d 100644 --- a/components/navigation_interception/navigation_params.h +++ b/components/navigation_interception/navigation_params.h
@@ -15,6 +15,7 @@ public: NavigationParams(const GURL& url, const content::Referrer& referrer, + int64_t navigation_id, bool has_user_gesture, bool is_post, ui::PageTransition page_transition_type, @@ -31,6 +32,10 @@ const GURL& url() const { return url_; } GURL& url() { return url_; } const content::Referrer& referrer() const { return referrer_; } + + // The ID of the NavigationHandle that this instance corresponds to, or 0 if + // this instance was not constructed from a NavigationHandle. + int64_t navigation_id() const { return navigation_id_; } bool has_user_gesture() const { return has_user_gesture_; } bool is_post() const { return is_post_; } ui::PageTransition transition_type() const { return transition_type_; } @@ -47,6 +52,7 @@ GURL url_; content::Referrer referrer_; + int64_t navigation_id_; bool has_user_gesture_; bool is_post_; ui::PageTransition transition_type_;
diff --git a/components/navigation_interception/navigation_params_android.cc b/components/navigation_interception/navigation_params_android.cc index 2563534..b84d3e9 100644 --- a/components/navigation_interception/navigation_params_android.cc +++ b/components/navigation_interception/navigation_params_android.cc
@@ -26,10 +26,11 @@ ConvertUTF8ToJavaString(env, params.referrer().url.spec()); return Java_NavigationParams_create( - env, jstring_url, jstring_referrer, params.is_post(), - params.has_user_gesture(), params.transition_type(), params.is_redirect(), - params.is_external_protocol(), params.is_main_frame(), - params.is_renderer_initiated(), has_user_gesture_carryover, + env, jstring_url, jstring_referrer, params.navigation_id(), + params.is_post(), params.has_user_gesture(), params.transition_type(), + params.is_redirect(), params.is_external_protocol(), + params.is_main_frame(), params.is_renderer_initiated(), + has_user_gesture_carryover, params.initiator_origin() ? params.initiator_origin()->CreateJavaObject() : nullptr); }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java index b0cb261..562a65d 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -488,6 +488,10 @@ mPendingRunAfterDismissTask.run(); mPendingRunAfterDismissTask = null; } + if (mSubpageController != null) { + mSubpageController.onSubpageRemoved(); + mSubpageController = null; + } mWebContentsObserver.destroy(); mWebContentsObserver = null; PageInfoControllerJni.get().destroy(mNativePageInfoController, PageInfoController.this); @@ -612,6 +616,9 @@ public void exitSubpage() { if (mSubpageController == null) return; mContainer.showPage(mView, null, () -> { + // The PageInfo dialog can get dismissed during the page change animation. + // In that case mSubpageController will already be null. + if (mSubpageController == null) return; mSubpageController.onSubpageRemoved(); mSubpageController = null; });
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java index 5b170292..bd2aa59 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java
@@ -122,10 +122,11 @@ public void onSubpageRemoved() { assert mSubPage != null; AppCompatActivity host = (AppCompatActivity) mRowView.getContext(); - PageInfoCookiesPreference subBage = mSubPage; + PageInfoCookiesPreference subPage = mSubPage; mSubPage = null; - if (host.isFinishing()) return; - host.getSupportFragmentManager().beginTransaction().remove(subBage).commitNow(); + // If the activity is getting destroyed or saved, it is not allowed to modify fragments. + if (host.isFinishing() || host.getSupportFragmentManager().isStateSaved()) return; + host.getSupportFragmentManager().beginTransaction().remove(subPage).commitNow(); } @Override
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java index bfa3f84..0dc23a4 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java
@@ -3,6 +3,7 @@ // found in the LICENSE file. package org.chromium.components.page_info; +import android.app.Dialog; import android.os.Bundle; import android.text.format.Formatter; @@ -30,6 +31,7 @@ private ChromeSwitchPreference mCookieSwitch; private ChromeImageViewPreference mCookieInUse; private Runnable mOnClearCallback; + private Dialog mConfirmationDialog; /** Parameters to configure the cookie controls view. */ public static class PageInfoCookiesViewParams { @@ -48,6 +50,14 @@ mCookieInUse = findPreference(COOKIE_IN_USE_PREFERENCE); } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (mConfirmationDialog != null) { + mConfirmationDialog.dismiss(); + } + } + public void setParams(PageInfoCookiesViewParams params) { Preference cookieSummary = findPreference(COOKIE_SUMMARY_PREFERENCE); NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan( @@ -81,13 +91,15 @@ } private void showClearCookiesConfirmation() { - new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog) - .setTitle(R.string.page_info_cookies_clear) - .setMessage(R.string.page_info_cookies_clear_confirmation) - .setPositiveButton(R.string.page_info_cookies_clear_confirmation_button, - (dialog, which) -> mOnClearCallback.run()) - .setNegativeButton(R.string.cancel, null) - .show(); + mConfirmationDialog = + new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog) + .setTitle(R.string.page_info_cookies_clear) + .setMessage(R.string.page_info_cookies_clear_confirmation) + .setPositiveButton(R.string.page_info_cookies_clear_confirmation_button, + (dialog, which) -> mOnClearCallback.run()) + .setNegativeButton( + R.string.cancel, (dialog, which) -> mConfirmationDialog = null) + .show(); } public void setCookieBlockingStatus(@CookieControlsStatus int status, boolean isEnforced) {
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java index fb30cfa..8b8f166 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
@@ -27,7 +27,7 @@ private PageInfoControllerDelegate mDelegate; private String mTitle; private String mPageUrl; - private SingleWebsiteSettings mSubpageFragment; + private SingleWebsiteSettings mSubPage; public PageInfoPermissionsController(PageInfoMainController mainController, PageInfoRowView view, PageInfoControllerDelegate delegate, String pageUrl) { @@ -49,26 +49,27 @@ @Override public View createViewForSubpage(ViewGroup parent) { - assert mSubpageFragment == null; + assert mSubPage == null; Bundle fragmentArgs = SingleWebsiteSettings.createFragmentArgsForSite(mPageUrl); - mSubpageFragment = (SingleWebsiteSettings) Fragment.instantiate( + mSubPage = (SingleWebsiteSettings) Fragment.instantiate( mRowView.getContext(), SingleWebsiteSettings.class.getName(), fragmentArgs); - mSubpageFragment.setSiteSettingsClient(mDelegate.getSiteSettingsClient()); - mSubpageFragment.setHideNonPermissionPreferences(true); - mSubpageFragment.setWebsiteSettingsObserver(this); + mSubPage.setSiteSettingsClient(mDelegate.getSiteSettingsClient()); + mSubPage.setHideNonPermissionPreferences(true); + mSubPage.setWebsiteSettingsObserver(this); AppCompatActivity host = (AppCompatActivity) mRowView.getContext(); - host.getSupportFragmentManager().beginTransaction().add(mSubpageFragment, null).commitNow(); - return mSubpageFragment.requireView(); + host.getSupportFragmentManager().beginTransaction().add(mSubPage, null).commitNow(); + return mSubPage.requireView(); } @Override public void onSubpageRemoved() { - assert mSubpageFragment != null; + assert mSubPage != null; AppCompatActivity host = (AppCompatActivity) mRowView.getContext(); - SingleWebsiteSettings fragment = mSubpageFragment; - mSubpageFragment = null; - if (host.isFinishing()) return; - host.getSupportFragmentManager().beginTransaction().remove(fragment).commitNow(); + SingleWebsiteSettings subPage = mSubPage; + mSubPage = null; + // If the activity is getting destroyed or saved, it is not allowed to modify fragments. + if (host.isFinishing() || host.getSupportFragmentManager().isStateSaved()) return; + host.getSupportFragmentManager().beginTransaction().remove(subPage).commitNow(); } public void setPermissions(PageInfoView.PermissionParams params) {
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java b/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java index 28ed87a0..565f679 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/BrowserPaymentRequest.java
@@ -207,11 +207,6 @@ return null; } - /** @return Whether any payment UI is being shown. */ - default boolean isShowingUi() { - return false; - } - /** * Continues the unfinished part of show() that was blocked for the payment details that was * pending to be updated.
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java index a6a8ab34a..14969ea 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentRequestService.java
@@ -97,7 +97,7 @@ private PaymentRequestSpec mSpec; private boolean mHasClosed; private boolean mIsFinishedQueryingPaymentApps; - private boolean mIsCurrentPaymentRequestShowing; + private boolean mIsShowCalled; private boolean mIsShowWaitingForUpdatedDetails; /** If not empty, use this error message for rejecting PaymentRequest.show(). */ @@ -282,6 +282,11 @@ String appLocale) { return new PaymentRequestSpec(options, details, methodData, appLocale); } + + /** @return The PaymentAppService that is used to create payment app for this service. */ + default PaymentAppService getPaymentAppService() { + return PaymentAppService.getInstance(); + } } /** @@ -376,15 +381,15 @@ if (renderFrameHost.getLastCommittedOrigin() == null || renderFrameHost.getLastCommittedURL() == null) { - abortBeforeInstantiation(/*client=*/null, /*journeyLogger=*/null, ErrorStrings.NO_FRAME, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + /*client=*/null, /*journeyLogger=*/null, ErrorStrings.NO_FRAME); return null; } WebContents webContents = delegate.getLiveWebContents(renderFrameHost); if (webContents == null || webContents.isDestroyed()) { - abortBeforeInstantiation(/*client=*/null, /*journeyLogger=*/null, - ErrorStrings.NO_WEB_CONTENTS, AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + /*client=*/null, /*journeyLogger=*/null, ErrorStrings.NO_WEB_CONTENTS); return null; } @@ -392,45 +397,43 @@ JourneyLogger journeyLogger = delegate.createJourneyLogger(isOffTheRecord, webContents); if (client == null) { - abortBeforeInstantiation(/*client=*/null, journeyLogger, ErrorStrings.INVALID_STATE, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + /*client=*/null, journeyLogger, ErrorStrings.INVALID_STATE); return null; } if (!delegate.isOriginSecure(webContents.getLastCommittedUrl())) { - abortBeforeInstantiation(client, journeyLogger, ErrorStrings.NOT_IN_A_SECURE_ORIGIN, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + client, journeyLogger, ErrorStrings.NOT_IN_A_SECURE_ORIGIN); return null; } if (methodData == null) { - abortBeforeInstantiation(client, journeyLogger, - ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + client, journeyLogger, ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA); return null; } for (PaymentMethodData datum : methodData) { if (datum == null || TextUtils.isEmpty(datum.supportedMethod)) { - abortBeforeInstantiation(client, journeyLogger, - ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + client, journeyLogger, ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA); return null; } } // details has default value, so could never be null, according to payment_request.idl. if (details == null || details.id == null || details.total == null) { - abortBeforeInstantiation(client, journeyLogger, ErrorStrings.INVALID_PAYMENT_DETAILS, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + client, journeyLogger, ErrorStrings.INVALID_PAYMENT_DETAILS); return null; } // options has default value, so could never be null, according to // payment_request.idl. if (options == null) { - abortBeforeInstantiation(client, journeyLogger, ErrorStrings.INVALID_PAYMENT_OPTIONS, - AbortReason.INVALID_DATA_FROM_RENDERER); + abortForInvalidDataFromRenderer( + client, journeyLogger, ErrorStrings.INVALID_PAYMENT_OPTIONS); return null; } @@ -447,7 +450,7 @@ } private void startPaymentAppService() { - PaymentAppService service = PaymentAppService.getInstance(); + PaymentAppService service = mDelegate.getPaymentAppService(); mBrowserPaymentRequest.addPaymentAppFactories(service, /*delegate=*/this); service.create(/*delegate=*/this); } @@ -492,12 +495,13 @@ } } - /** Abort the request, used before this class's instantiation. */ - private static void abortBeforeInstantiation(@Nullable PaymentRequestClient client, - @Nullable JourneyLogger journeyLogger, String debugMessage, int reason) { + private static void abortForInvalidDataFromRenderer(@Nullable PaymentRequestClient client, + @Nullable JourneyLogger journeyLogger, String debugMessage) { Log.d(TAG, debugMessage); - if (client != null) client.onError(reason, debugMessage); - if (journeyLogger != null) journeyLogger.setAborted(reason); + if (client != null) { + client.onError(PaymentErrorReason.INVALID_DATA_FROM_RENDERER, debugMessage); + } + if (journeyLogger != null) journeyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); if (sNativeObserverForTest != null) sNativeObserverForTest.onConnectionTerminated(); } @@ -588,8 +592,8 @@ mBrowserPaymentRequest.modifyMethodDataIfNeeded(methodData); if (methodData == null) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); - disconnectFromClientWithDebugMessage( - ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, PaymentErrorReason.USER_CANCEL); + disconnectFromClientWithDebugMessage(ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); return false; } methodData = Collections.unmodifiableMap(methodData); @@ -600,8 +604,8 @@ if (details == null || details.id == null || details.total == null || !mDelegate.validatePaymentDetails(details)) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); - disconnectFromClientWithDebugMessage( - ErrorStrings.INVALID_PAYMENT_DETAILS, PaymentErrorReason.USER_CANCEL); + disconnectFromClientWithDebugMessage(ErrorStrings.INVALID_PAYMENT_DETAILS, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); return false; } @@ -615,7 +619,7 @@ if (spec.getRawTotal() == null) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); disconnectFromClientWithDebugMessage( - ErrorStrings.TOTAL_REQUIRED, PaymentErrorReason.USER_CANCEL); + ErrorStrings.TOTAL_REQUIRED, PaymentErrorReason.INVALID_DATA_FROM_RENDERER); return false; } mSpec = spec; @@ -762,7 +766,7 @@ mBrowserPaymentRequest.notifyPaymentUiOfPendingApps(mPendingApps); mPendingApps.clear(); - if (isCurrentPaymentRequestShowing()) { + if (mIsShowCalled) { String error = mBrowserPaymentRequest.showAppSelector(mIsShowWaitingForUpdatedDetails, mSpec.getRawTotal(), mSpec.getPaymentOptions(), mIsUserGestureShow); if (error != null) { @@ -796,7 +800,7 @@ * @return Whether client has been disconnected. */ private boolean disconnectIfNoPaymentMethodsSupported(boolean hasAvailableApps) { - if (!mIsFinishedQueryingPaymentApps || !isCurrentPaymentRequestShowing()) return false; + if (!mIsFinishedQueryingPaymentApps || !mIsShowCalled) return false; if (!mCanMakePayment || (mPendingApps.isEmpty() && !hasAvailableApps)) { // All factories have responded, but none of them have apps. It's possible to add credit // cards, but the merchant does not support them either. The payment request must be @@ -862,11 +866,6 @@ return mIsUserGestureShow; } - /** @return Whether the current payment request service has called show(). */ - public boolean isCurrentPaymentRequestShowing() { - return mIsCurrentPaymentRequestShowing; - } - /** * @return Whether all payment apps have been queried of canMakePayment() and * hasEnrolledInstrument(). @@ -1007,6 +1006,11 @@ return result; } + @VisibleForTesting + public static void resetShowingPaymentRequestForTest() { + sShowingPaymentRequest = null; + } + /** * The component part of the {@link PaymentRequest#show} implementation. Check {@link * PaymentRequest#show} for the parameters' specification. @@ -1016,7 +1020,7 @@ assert mSpec != null; assert !mSpec.isDestroyed() : "mSpec is destroyed only after close()."; - if (mBrowserPaymentRequest.isShowingUi()) { + if (mIsShowCalled) { // Can be triggered only by a compromised renderer. In normal operation, calling show() // twice on the same instance of PaymentRequest in JavaScript is rejected at the // renderer level. @@ -1035,7 +1039,7 @@ } sShowingPaymentRequest = this; mJourneyLogger.recordCheckoutStep(CheckoutFunnelStep.SHOW_CALLED); - mIsCurrentPaymentRequestShowing = true; + mIsShowCalled = true; mIsUserGestureShow = isUserGesture; mIsShowWaitingForUpdatedDetails = waitForUpdatedDetails; @@ -1062,7 +1066,7 @@ // Return the error if failed, null if success. @Nullable private String triggerPaymentAppUiSkipIfApplicable() { - if (!mIsFinishedQueryingPaymentApps || !mIsCurrentPaymentRequestShowing + if (mHasClosed || !mIsFinishedQueryingPaymentApps || !mIsShowCalled || mIsShowWaitingForUpdatedDetails) { return null; } @@ -1192,7 +1196,7 @@ return; } - if (!mIsCurrentPaymentRequestShowing) { + if (!mIsShowCalled) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); disconnectFromClientWithDebugMessage( ErrorStrings.CANNOT_UPDATE_WITHOUT_SHOW, PaymentErrorReason.USER_CANCEL); @@ -1237,7 +1241,7 @@ */ /* package */ void onPaymentDetailsNotUpdated() { if (mBrowserPaymentRequest == null) return; - if (!mIsCurrentPaymentRequestShowing) { + if (!mIsShowCalled) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); disconnectFromClientWithDebugMessage( ErrorStrings.CANNOT_UPDATE_WITHOUT_SHOW, PaymentErrorReason.USER_CANCEL); @@ -1370,7 +1374,8 @@ */ /* package */ void abortForInvalidDataFromRenderer(String debugMessage) { mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER); - disconnectFromClientWithDebugMessage(debugMessage, PaymentErrorReason.USER_CANCEL); + disconnectFromClientWithDebugMessage( + debugMessage, PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } /** @@ -1382,7 +1387,6 @@ if (mHasClosed) return; mHasClosed = true; - mIsCurrentPaymentRequestShowing = false; sShowingPaymentRequest = null; if (mBrowserPaymentRequest != null) {
diff --git a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java index 15769f5f..b17c969 100644 --- a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java +++ b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceBuilder.java
@@ -29,6 +29,7 @@ private final Delegate mDelegate; private final RenderFrameHost mRenderFrameHost; private final Runnable mOnClosedListener; + private final PaymentAppService mPaymentAppService; private final Factory mBrowserPaymentRequestFactory; private WebContents mWebContents; private boolean mIsOffTheRecord = true; @@ -48,12 +49,14 @@ private PaymentRequestSpec mSpec; /* package */ static PaymentRequestServiceBuilder defaultBuilder(Runnable onClosedListener, - PaymentRequestClient client, BrowserPaymentRequest browserPaymentRequest) { - return new PaymentRequestServiceBuilder(onClosedListener, client, browserPaymentRequest); + PaymentRequestClient client, PaymentAppService appService, + BrowserPaymentRequest browserPaymentRequest) { + return new PaymentRequestServiceBuilder( + onClosedListener, client, appService, browserPaymentRequest); } private PaymentRequestServiceBuilder(Runnable onClosedListener, PaymentRequestClient client, - BrowserPaymentRequest browserPaymentRequest) { + PaymentAppService appService, BrowserPaymentRequest browserPaymentRequest) { mDelegate = this; mWebContents = Mockito.mock(WebContents.class); setTopLevelOrigin("https://top.level.origin"); @@ -76,6 +79,7 @@ mBrowserPaymentRequestFactory = (paymentRequestService) -> browserPaymentRequest; mOnClosedListener = onClosedListener; mClient = client; + mPaymentAppService = appService; } @Override @@ -141,6 +145,11 @@ return mSpec; } + @Override + public PaymentAppService getPaymentAppService() { + return mPaymentAppService; + } + /* package */ PaymentRequestServiceBuilder setRenderFrameHostLastCommittedOrigin( Origin origin) { Mockito.doReturn(origin).when(mRenderFrameHost).getLastCommittedOrigin();
diff --git a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceTest.java b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceTest.java index bd801518..44c4c8f 100644 --- a/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceTest.java +++ b/components/payments/content/android/junit/src/org/chromium/components/payments/PaymentRequestServiceTest.java
@@ -4,7 +4,9 @@ package org.chromium.components.payments; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -20,17 +22,23 @@ import org.chromium.mojo.system.MojoException; import org.chromium.payments.mojom.PayerDetail; import org.chromium.payments.mojom.PaymentAddress; +import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentErrorReason; import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentRequestClient; import org.chromium.payments.mojom.PaymentResponse; +import java.util.ArrayList; +import java.util.List; + /** A test for PaymentRequestService. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) public class PaymentRequestServiceTest implements PaymentRequestClient { private static final int NO_PAYMENT_ERROR = PaymentErrorReason.MIN_VALUE; private final BrowserPaymentRequest mBrowserPaymentRequest; + private List<PaymentApp> mNotifiedPendingApps; + @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.WARN); @@ -50,9 +58,53 @@ private boolean mWarnNoFaviconCalled; private boolean mIsClientClosed; private MojoException mConnectionError; + private boolean mIsUserGestureDefaultValue = true; + private boolean mWaitForUpdatedDetailsDefaultValue; + private PaymentAppService mPaymentAppService; + private PaymentAppFactoryDelegate mPaymentAppFactoryDelegate; public PaymentRequestServiceTest() { + mPaymentAppService = Mockito.mock(PaymentAppService.class); + Mockito.doAnswer((args) -> { + mPaymentAppFactoryDelegate = args.getArgument(0); + return null; + }) + .when(mPaymentAppService) + .create(Mockito.any()); + mBrowserPaymentRequest = Mockito.mock(BrowserPaymentRequest.class); + Mockito.doReturn(true).when(mBrowserPaymentRequest).hasAvailableApps(); + Mockito.doReturn(false) + .when(mBrowserPaymentRequest) + .disconnectIfExtraValidationFails( + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); + Mockito.doReturn(true) + .when(mBrowserPaymentRequest) + .patchPaymentResponseIfNeeded(Mockito.any()); + Mockito.doReturn(null) + .when(mBrowserPaymentRequest) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + Mockito.doReturn(true) + .when(mBrowserPaymentRequest) + .parseAndValidateDetailsFurtherIfNeeded(Mockito.any()); + Mockito.doAnswer((args) -> { + List<PaymentApp> pendingApps = args.getArgument(0); + mNotifiedPendingApps = new ArrayList<>(pendingApps); + return null; + }) + .when(mBrowserPaymentRequest) + .notifyPaymentUiOfPendingApps(Mockito.any()); + } + + @Before + public void setUp() { + PaymentRequestService.resetShowingPaymentRequestForTest(); + } + + @After + public void tearDown() { + PaymentRequestService.resetShowingPaymentRequestForTest(); } @Override @@ -131,9 +183,37 @@ Assert.assertEquals(errorReason, mSentErrorReason); } + private void assertClosed(boolean isClosed) { + Assert.assertEquals(mIsClientClosed, isClosed); + Assert.assertEquals(mIsOnCloseListenerInvoked, isClosed); + } + + private void show(PaymentRequestService service) { + service.show(mIsUserGestureDefaultValue, mWaitForUpdatedDetailsDefaultValue); + } + private PaymentRequestServiceBuilder defaultBuilder() { return PaymentRequestServiceBuilder.defaultBuilder( - () -> mIsOnCloseListenerInvoked = true, /*client=*/this, mBrowserPaymentRequest); + () + -> mIsOnCloseListenerInvoked = true, + /*client=*/this, mPaymentAppService, mBrowserPaymentRequest); + } + + private PaymentApp createDefaultPaymentApp() { + PaymentApp app = Mockito.mock(PaymentApp.class); + Mockito.doReturn(true).when(app).canMakePayment(); + Mockito.doReturn(false).when(app).isAutofillInstrument(); + return app; + } + + private void queryPaymentApps() { + mPaymentAppFactoryDelegate.onCanMakePaymentCalculated(true); + mPaymentAppFactoryDelegate.onPaymentAppCreated(createDefaultPaymentApp()); + mPaymentAppFactoryDelegate.onDoneCreatingPaymentApps(null); + } + + private PaymentDetails getDefaultDetails() { + return new PaymentDetails(); } @Test @@ -177,24 +257,32 @@ @Feature({"Payments"}) public void testInsecureOriginFailsCreation() { Assert.assertNull(defaultBuilder().setOriginSecure(false).build()); + assertErrorAndReason( + ErrorStrings.NOT_IN_A_SECURE_ORIGIN, PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @Feature({"Payments"}) public void testNullMethodDataFailsCreation() { Assert.assertNull(defaultBuilder().setMethodData(null).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @Feature({"Payments"}) public void testNullDetailsFailsCreation() { Assert.assertNull(defaultBuilder().setDetails(null).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_DETAILS, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @Feature({"Payments"}) public void testNullOptionsFailsCreation() { Assert.assertNull(defaultBuilder().setOptions(null).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_OPTIONS, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @@ -219,6 +307,8 @@ public void testMethodDataNullElementFailsCreation() { PaymentMethodData[] methodData = new PaymentMethodData[1]; Assert.assertNull(defaultBuilder().setMethodData(methodData).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @@ -228,6 +318,8 @@ methodData[0] = new PaymentMethodData(); methodData[0].supportedMethod = ""; Assert.assertNull(defaultBuilder().setMethodData(methodData).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @@ -237,13 +329,16 @@ methodData[0] = new PaymentMethodData(); methodData[0].supportedMethod = null; Assert.assertNull(defaultBuilder().setMethodData(methodData).build()); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_METHODS_OR_DATA, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @Feature({"Payments"}) public void testInvalidDetailsFailsCreation() { Assert.assertNull(defaultBuilder().setIsPaymentDetailsValid(false).build()); - assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_DETAILS, PaymentErrorReason.USER_CANCEL); + assertErrorAndReason(ErrorStrings.INVALID_PAYMENT_DETAILS, + PaymentErrorReason.INVALID_DATA_FROM_RENDERER); } @Test @@ -252,15 +347,146 @@ PaymentRequestSpec spec = Mockito.mock(PaymentRequestSpec.class); Mockito.doReturn(null).when(spec).getRawTotal(); Assert.assertNull(defaultBuilder().setPaymentRequestSpec(spec).build()); - assertErrorAndReason(ErrorStrings.TOTAL_REQUIRED, PaymentErrorReason.USER_CANCEL); + assertErrorAndReason( + ErrorStrings.TOTAL_REQUIRED, PaymentErrorReason.INVALID_DATA_FROM_RENDERER); + } + + @Test + @Feature({"Payments"}) + public void testTwoShowsFailService() { + PaymentRequestService service = defaultBuilder().build(); + show(service); + assertErrorAndReason(null, NO_PAYMENT_ERROR); + assertClosed(false); + show(service); + assertErrorAndReason(ErrorStrings.CANNOT_SHOW_TWICE, PaymentErrorReason.USER_CANCEL); + assertClosed(true); } @Test @Feature({"Payments"}) public void testDefaultParamsMakeCreationSuccess() { + Assert.assertNull(mPaymentAppFactoryDelegate); PaymentRequestService service = defaultBuilder().build(); Assert.assertNotNull(service); Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)).onSpecValidated(Mockito.notNull()); assertNoError(); + Assert.assertNotNull(mPaymentAppFactoryDelegate); + } + + @Test + @Feature({"Payments"}) + public void testCanNotMakePaymentFailsPayment() { + PaymentRequestService service = defaultBuilder().build(); + show(service); + mPaymentAppFactoryDelegate.onCanMakePaymentCalculated(false); + mPaymentAppFactoryDelegate.onPaymentAppCreated(createDefaultPaymentApp()); + mPaymentAppFactoryDelegate.onDoneCreatingPaymentApps(null); + assertErrorAndReason(ErrorStrings.USER_CANCELLED, PaymentErrorReason.USER_CANCEL); + assertClosed(true); + } + + @Test + @Feature({"Payments"}) + public void testNoPaymentAppFailsPayment() { + PaymentRequestService service = defaultBuilder().build(); + show(service); + mPaymentAppFactoryDelegate.onDoneCreatingPaymentApps(null); + assertErrorAndReason(ErrorStrings.USER_CANCELLED, PaymentErrorReason.USER_CANCEL); + assertClosed(true); + } + + @Test + @Feature({"Payments"}) + public void testAppSelectorIsTriggeredOnShownAndAppsQueried() { + PaymentRequestService service = defaultBuilder().build(); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + show(service); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + queryPaymentApps(); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + } + + @Test + @Feature({"Payments"}) + public void testUiIsNotifiedOfPendingAppsOnShownAndAppsQueried() { + PaymentRequestService service = defaultBuilder().build(); + show(service); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .notifyPaymentUiOfPendingApps(Mockito.any()); + Assert.assertNull(mNotifiedPendingApps); + queryPaymentApps(); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) + .notifyPaymentUiOfPendingApps(Mockito.any()); + Assert.assertEquals(1, mNotifiedPendingApps.size()); + } + + @Test + @Feature({"Payments"}) + public void testAppSelectorIsNotTriggeredOnAppsQueriedOnly() { + PaymentRequestService service = defaultBuilder().build(); + queryPaymentApps(); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + show(service); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) + .showAppSelector( + Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()); + } + + @Test + @Feature({"Payments"}) + public void testInvokeUiSkipMethodOnShownAndAppsQueried() { + PaymentRequestService service = defaultBuilder().build(); + show(service); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .triggerPaymentAppUiSkipIfApplicable(Mockito.anyBoolean()); + queryPaymentApps(); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) + .triggerPaymentAppUiSkipIfApplicable(Mockito.anyBoolean()); + } + + @Test + @Feature({"Payments"}) + public void testWaitingForUpdatedDetailsDeterUiSkipMethod() { + PaymentRequestService service = defaultBuilder().build(); + service.show(mIsUserGestureDefaultValue, true); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .triggerPaymentAppUiSkipIfApplicable(Mockito.anyBoolean()); + queryPaymentApps(); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()) + .triggerPaymentAppUiSkipIfApplicable(Mockito.anyBoolean()); + service.updateWith(getDefaultDetails()); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) + .triggerPaymentAppUiSkipIfApplicable(Mockito.anyBoolean()); + } + + @Test + @Feature({"Payments"}) + public void testCloseTeardownResources() { + PaymentRequestService service = defaultBuilder().build(); + Mockito.verify(mBrowserPaymentRequest, Mockito.never()).close(); + assertClosed(false); + service.close(); + Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)).close(); + assertClosed(true); + } + + @Test + @Feature({"Payments"}) + public void testOnlyOneServiceCanBeShownGlobally() { + PaymentRequestService service1 = defaultBuilder().build(); + show(service1); + assertNoError(); + PaymentRequestService service2 = defaultBuilder().build(); + show(service2); + assertErrorAndReason(ErrorStrings.ANOTHER_UI_SHOWING, PaymentErrorReason.ALREADY_SHOWING); } }
diff --git a/components/permissions/BUILD.gn b/components/permissions/BUILD.gn index 4861029..9edc62b 100644 --- a/components/permissions/BUILD.gn +++ b/components/permissions/BUILD.gn
@@ -63,6 +63,7 @@ ] deps = [ "//base", + "//build:chromeos_buildflags", "//components/autofill_assistant/browser/public:public", "//components/content_settings/browser", "//components/content_settings/core/browser", @@ -159,6 +160,7 @@ ":test_support", "//base", "//base/test:test_support", + "//build:chromeos_buildflags", "//components/content_settings/browser", "//components/content_settings/browser:test_support", "//components/content_settings/core/browser",
diff --git a/components/permissions/permission_context_base_unittest.cc b/components/permissions/permission_context_base_unittest.cc index 21db013b..94c6811 100644 --- a/components/permissions/permission_context_base_unittest.cc +++ b/components/permissions/permission_context_base_unittest.cc
@@ -19,6 +19,7 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" @@ -765,7 +766,7 @@ TestRequestPermissionInvalidUrl(ContentSettingsType::GEOLOCATION); TestRequestPermissionInvalidUrl(ContentSettingsType::NOTIFICATIONS); TestRequestPermissionInvalidUrl(ContentSettingsType::MIDI_SYSEX); -#if defined(OS_CHROMEOS) +#if BUILDFLAG(IS_CHROMEOS_ASH) TestRequestPermissionInvalidUrl( ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER); #endif @@ -795,7 +796,7 @@ TestGlobalPermissionsKillSwitch(ContentSettingsType::NOTIFICATIONS); TestGlobalPermissionsKillSwitch(ContentSettingsType::MIDI_SYSEX); TestGlobalPermissionsKillSwitch(ContentSettingsType::DURABLE_STORAGE); -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) TestGlobalPermissionsKillSwitch( ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER); #endif
diff --git a/components/permissions/permission_manager.cc b/components/permissions/permission_manager.cc index 40a9b555..6ff3c23 100644 --- a/components/permissions/permission_manager.cc +++ b/components/permissions/permission_manager.cc
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/feature_list.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/permissions/features.h" #include "components/permissions/permission_context_base.h" @@ -81,7 +82,7 @@ case PermissionType::GEOLOCATION: return ContentSettingsType::GEOLOCATION; case PermissionType::PROTECTED_MEDIA_IDENTIFIER: -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) return ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER; #else break;
diff --git a/components/permissions/permission_manager_unittest.cc b/components/permissions/permission_manager_unittest.cc index ce6ba4d..6ad48c0 100644 --- a/components/permissions/permission_manager_unittest.cc +++ b/components/permissions/permission_manager_unittest.cc
@@ -11,6 +11,7 @@ #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/permissions/features.h" #include "components/permissions/permission_context_base.h" @@ -658,7 +659,7 @@ TEST_F(PermissionManagerTest, MissingContextIsNotOverridable) { // Permissions that are not implemented should be denied overridability. -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) EXPECT_FALSE( GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools( PermissionType::PROTECTED_MEDIA_IDENTIFIER,
diff --git a/components/permissions/permission_request_impl.cc b/components/permissions/permission_request_impl.cc index 8458de2..2c59219 100644 --- a/components/permissions/permission_request_impl.cc +++ b/components/permissions/permission_request_impl.cc
@@ -6,6 +6,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/permissions/permission_util.h" #include "components/permissions/permissions_client.h" #include "components/strings/grit/components_strings.h" @@ -199,7 +200,7 @@ case ContentSettingsType::MIDI_SYSEX: message_id = IDS_MIDI_SYSEX_PERMISSION_FRAGMENT; break; -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER: message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT; break;
diff --git a/components/permissions/permission_util.cc b/components/permissions/permission_util.cc index 9bf867a3..9567d4bc 100644 --- a/components/permissions/permission_util.cc +++ b/components/permissions/permission_util.cc
@@ -6,6 +6,7 @@ #include "base/notreached.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "content/public/browser/permission_type.h" using content::PermissionType; @@ -147,7 +148,7 @@ *out = PermissionType::BACKGROUND_SYNC; } else if (type == ContentSettingsType::PLUGINS) { *out = PermissionType::FLASH; -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) } else if (type == ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER) { *out = PermissionType::PROTECTED_MEDIA_IDENTIFIER; #endif @@ -199,7 +200,7 @@ case ContentSettingsType::MEDIASTREAM_MIC: case ContentSettingsType::BACKGROUND_SYNC: case ContentSettingsType::PLUGINS: -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER: #endif case ContentSettingsType::SENSORS:
diff --git a/components/permissions/permissions_client.cc b/components/permissions/permissions_client.cc index 19fa0bf..f6b8828 100644 --- a/components/permissions/permissions_client.cc +++ b/components/permissions/permissions_client.cc
@@ -5,6 +5,7 @@ #include "components/permissions/permissions_client.h" #include "base/callback.h" +#include "build/chromeos_buildflags.h" #include "components/permissions/notification_permission_ui_selector.h" #if !defined(OS_ANDROID) @@ -44,7 +45,7 @@ entry.second = false; } -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) bool PermissionsClient::IsCookieDeletionDisabled( content::BrowserContext* browser_context, const GURL& origin) {
diff --git a/components/permissions/permissions_client.h b/components/permissions/permissions_client.h index c8e8c1f..b73234c 100644 --- a/components/permissions/permissions_client.h +++ b/components/permissions/permissions_client.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/permissions/notification_permission_ui_selector.h" #include "components/permissions/permission_prompt.h" @@ -95,7 +96,7 @@ content::BrowserContext* browser_context, std::vector<std::pair<url::Origin, bool>>* origins); -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) +#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) // Returns whether cookie deletion is allowed for |browser_context| and // |origin|. // TODO(crbug.com/1081944): Remove this method and all code depending on it
diff --git a/components/permissions/prediction_service/BUILD.gn b/components/permissions/prediction_service/BUILD.gn index 96b42b9..0a8f8ca 100644 --- a/components/permissions/prediction_service/BUILD.gn +++ b/components/permissions/prediction_service/BUILD.gn
@@ -18,6 +18,7 @@ "prediction_service_common.h", ] deps = [ + "//build:chromeos_buildflags", "//components/keyed_service/content", "//components/permissions:permissions_common", "//services/network/public/cpp:cpp",
diff --git a/components/permissions/prediction_service/prediction_service_common.cc b/components/permissions/prediction_service/prediction_service_common.cc index 02dbf47..448a333 100644 --- a/components/permissions/prediction_service/prediction_service_common.cc +++ b/components/permissions/prediction_service/prediction_service_common.cc
@@ -5,12 +5,13 @@ #include "components/permissions/prediction_service/prediction_service_common.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace permissions { ClientFeatures_Platform GetCurrentPlatformProto() { #if defined(OS_WIN) return permissions::ClientFeatures_Platform_PLATFORM_WINDOWS; -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) return permissions::ClientFeatures_Platform_PLATFORM_LINUX; #elif defined(OS_ANDROID) return permissions::ClientFeatures_Platform_PLATFORM_ANDROID;
diff --git a/components/policy/core/common/config_dir_policy_loader.cc b/components/policy/core/common/config_dir_policy_loader.cc index dd39dfa..74d0a03 100644 --- a/components/policy/core/common/config_dir_policy_loader.cc +++ b/components/policy/core/common/config_dir_policy_loader.cc
@@ -67,9 +67,11 @@ DCHECK(task_runner_->RunsTasksInCurrentSequence()); base::FilePathWatcher::Callback callback = base::BindRepeating( &ConfigDirPolicyLoader::OnFileUpdated, base::Unretained(this)); - mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), false, + mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), + base::FilePathWatcher::Type::kNonRecursive, callback); - recommended_watcher_.Watch(config_dir_.Append(kRecommendedConfigDir), false, + recommended_watcher_.Watch(config_dir_.Append(kRecommendedConfigDir), + base::FilePathWatcher::Type::kNonRecursive, callback); }
diff --git a/components/policy/core/common/policy_loader_mac.mm b/components/policy/core/common/policy_loader_mac.mm index 35005d02..f56505d1 100644 --- a/components/policy/core/common/policy_loader_mac.mm +++ b/components/policy/core/common/policy_loader_mac.mm
@@ -77,7 +77,8 @@ void PolicyLoaderMac::InitOnBackgroundThread() { if (!managed_policy_path_.empty()) { - watcher_.Watch(managed_policy_path_, false, + watcher_.Watch(managed_policy_path_, + base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this))); }
diff --git a/components/policy/tools/template_writers/writers/jamf_writer.py b/components/policy/tools/template_writers/writers/jamf_writer.py index e00ac95..e87cd15 100755 --- a/components/policy/tools/template_writers/writers/jamf_writer.py +++ b/components/policy/tools/template_writers/writers/jamf_writer.py
@@ -80,6 +80,7 @@ policies = [policy for policy in policies if self.IsPolicySupported(policy)] output = { 'title': self.config['bundle_id'], + 'version': self.config['version'].split(".", 1)[0], 'description': self.config['app_name'], 'options': { 'remove_empty_properties': True
diff --git a/components/policy/tools/template_writers/writers/jamf_writer_unittest.py b/components/policy/tools/template_writers/writers/jamf_writer_unittest.py index 6e94821..1ab69c4 100755 --- a/components/policy/tools/template_writers/writers/jamf_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/jamf_writer_unittest.py
@@ -60,7 +60,7 @@ return _JsonFormat(template) def _GetExpectedOutput(self, policy_name, policy_type, policy_caption, - initial_type): + initial_type, version): output = { 'description': 'Google Chrome', 'options': { @@ -73,7 +73,8 @@ 'type': policy_type } }, - 'title': 'com.google.chrome.ios' + 'title': 'com.google.chrome.ios', + 'version': version } if initial_type == 'int-enum' or initial_type == 'string-enum': output['properties'][policy_name]['enum'] = [1] @@ -103,16 +104,22 @@ policy_json = self._GetTestPolicyTemplate('stringPolicy', 'string', '', 'A string policy') expected = self._GetExpectedOutput('stringPolicy', 'string', - 'A string policy', 'string') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'A string policy', 'string', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testIntPolicy(self): policy_json = self._GetTestPolicyTemplate('intPolicy', 'int', '', 'An int policy') expected = self._GetExpectedOutput('intPolicy', 'integer', 'An int policy', - 'int') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'int', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testIntPolicyWithMinAndMax(self): @@ -150,27 +157,38 @@ 'type': 'integer' } }, - 'title': 'com.google.chrome.ios' + 'title': 'com.google.chrome.ios', + 'version': '83' } expected_json = _JsonFormat(expected) - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected_json.strip()) def testIntEnumPolicy(self): policy_json = self._GetTestPolicyTemplate('intPolicy', 'int-enum', '', 'An int-enum policy') expected = self._GetExpectedOutput('intPolicy', 'integer', - 'An int-enum policy', 'int-enum') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'An int-enum policy', 'int-enum', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testStringEnumPolicy(self): policy_json = self._GetTestPolicyTemplate('stringPolicy', 'string-enum', '', 'A string-enum policy') expected = self._GetExpectedOutput('stringPolicy', 'string', - 'A string-enum policy', 'string-enum') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'A string-enum policy', 'string-enum', + '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testStringEnumListPolicy(self): @@ -179,40 +197,55 @@ 'A string-enum-list policy') expected = self._GetExpectedOutput('stringPolicy', 'array', 'A string-enum-list policy', - 'string-enum-list') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'string-enum-list', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testBooleanPolicy(self): policy_json = self._GetTestPolicyTemplate('booleanPolicy', 'main', '', 'A boolean policy') expected = self._GetExpectedOutput('booleanPolicy', 'boolean', - 'A boolean policy', 'main') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'A boolean policy', 'main', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testListPolicy(self): policy_json = self._GetTestPolicyTemplate('listPolicy', 'list', '', 'A list policy') expected = self._GetExpectedOutput('listPolicy', 'array', 'A list policy', - 'list') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'list', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testDictPolicy(self): policy_json = self._GetTestPolicyTemplate('dictPolicy', 'dict', 'object', 'A dict policy') expected = self._GetExpectedOutput('dictPolicy', 'object', 'A dict policy', - 'dict') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'dict', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testArrayDictPolicy(self): policy_json = self._GetTestPolicyTemplate('dictPolicy', 'dict', 'array', 'A dict policy') expected = self._GetExpectedOutput('dictPolicy', 'array', 'A dict policy', - 'dict') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'dict', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip()) def testNestedArrayDict(self): @@ -268,7 +301,8 @@ } } }, - 'title': 'com.google.chrome.ios' + 'title': 'com.google.chrome.ios', + 'version': '83' } for i in range(0, 5): @@ -278,15 +312,21 @@ } output_expected = _JsonFormat(expected) - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), output_expected.strip()) def testExternalPolicy(self): policy_json = self._GetTestPolicyTemplate('externalPolicy', 'external', '', 'A external policy') expected = self._GetExpectedOutput('externalPolicy', 'object', - 'A external policy', 'external') - output = self.GetOutput(policy_json, {'_google_chrome': '1'}, 'jamf') + 'A external policy', 'external', '83') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'jamf') self.assertEquals(output.strip(), expected.strip())
diff --git a/components/security_interstitials/content/BUILD.gn b/components/security_interstitials/content/BUILD.gn index f722af2..629d27a 100644 --- a/components/security_interstitials/content/BUILD.gn +++ b/components/security_interstitials/content/BUILD.gn
@@ -77,6 +77,7 @@ ":proto", "//base", "//build:branding_buildflags", + "//build:chromeos_buildflags", "//components/captive_portal/core", "//components/content_settings/core/browser", "//components/content_settings/core/common", @@ -151,6 +152,7 @@ ":security_interstitial_page", "//base", "//base/test:test_support", + "//build:chromeos_buildflags", "//components/captive_portal/content", "//components/captive_portal/core:test_support", "//components/embedder_support",
diff --git a/components/security_interstitials/content/certificate_error_report_unittest.cc b/components/security_interstitials/content/certificate_error_report_unittest.cc index 7940f40..8433e169 100644 --- a/components/security_interstitials/content/certificate_error_report_unittest.cc +++ b/components/security_interstitials/content/certificate_error_report_unittest.cc
@@ -17,6 +17,7 @@ #include "base/time/default_clock.h" #include "base/time/default_tick_clock.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #include "components/network_time/network_time_test_utils.h" #include "components/prefs/testing_pref_service.h" #include "components/security_interstitials/content/cert_logger.pb.h" @@ -286,7 +287,7 @@ } } -#if defined(OS_WIN) || defined(OS_CHROMEOS) +#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) // Tests that the SetIsEnterpriseManaged() function populates // is_enterprise_managed correctly on Windows, and that value is correctly // extracted from the parsed report.
diff --git a/components/security_interstitials/content/utils.cc b/components/security_interstitials/content/utils.cc index cbafd50..906016f 100644 --- a/components/security_interstitials/content/utils.cc +++ b/components/security_interstitials/content/utils.cc
@@ -8,6 +8,7 @@ #include "base/files/file_util.h" #include "base/process/launch.h" #include "build/build_config.h" +#include "build/chromeos_buildflags.h" #if defined(OS_ANDROID) #include "base/android/jni_android.h" @@ -24,7 +25,7 @@ namespace security_interstitials { -#if !defined(OS_CHROMEOS) && !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_FUCHSIA) void LaunchDateAndTimeSettings() { // The code for each OS is completely separate, in order to avoid bugs like // https://crbug.com/430877 .
diff --git a/components/security_interstitials/content/utils.h b/components/security_interstitials/content/utils.h index e643e93..beb25a8 100644 --- a/components/security_interstitials/content/utils.h +++ b/components/security_interstitials/content/utils.h
@@ -6,12 +6,13 @@ #define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_UTILS_H_ #include "build/build_config.h" +#include "build/chromeos_buildflags.h" namespace security_interstitials { // Provides utilities for security interstitials on //content-based platforms. -#if !defined(OS_CHROMEOS) && !defined(OS_FUCHSIA) +#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_FUCHSIA) // Launches date and time settings as appropriate based on the platform (not // supported on ChromeOS, where taking this action requires embedder-level // machinery, or Fuchsia, which simply doesn't require this functionality).
diff --git a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc index cad98d3..14fc8ca 100644 --- a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc +++ b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
@@ -40,6 +40,9 @@ #endif namespace { + +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + // Simple wrapper around a static string; used to avoid implicit conversion // of the account key to an std::string (which is the type used for account // identifier). This is a POD type so it can be used for static storage const @@ -274,9 +277,11 @@ void IssueAccessToken(AccountKey account_key) { fake_oauth2_token_service_.IssueAllTokensForAccount( AccountKeyToAccountId(account_key), - OAuth2AccessTokenConsumer::TokenResponse( - base::StringPrintf("access_token-%s", account_key.value), - base::Time::Max(), std::string())); + TokenResponseBuilder() + .WithAccessToken( + base::StringPrintf("access_token-%s", account_key.value)) + .WithExpirationTime(base::Time::Max()) + .build()); } std::string GenerateValidTokenInfoResponse(AccountKey account_key) {
diff --git a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc index 2f24cb3..660b591 100644 --- a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc +++ b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
@@ -5,8 +5,8 @@ #include "components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h" #include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" namespace { // Values used from |MutableProfileOAuth2TokenServiceDelegate|. @@ -47,8 +47,9 @@ OAuth2AccessTokenConsumer* consumer) { auto it = refresh_tokens_.find(account_id); DCHECK(it != refresh_tokens_.end()); - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory, it->second->refresh_token); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory, it->second->refresh_token); } bool FakeProfileOAuth2TokenServiceDelegate::RefreshTokenIsAvailable(
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service_unittest.cc b/components/signin/internal/identity_manager/gaia_cookie_manager_service_unittest.cc index e135e8d..07e05e33 100644 --- a/components/signin/internal/identity_manager/gaia_cookie_manager_service_unittest.cc +++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service_unittest.cc
@@ -35,6 +35,8 @@ namespace { +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + const char kAccountId1[] = "account_id1"; const char kAccountId2[] = "account_id2"; const char kAccountId3[] = "account_id3"; @@ -154,10 +156,10 @@ void SimulateAccessTokenSuccess(OAuth2AccessTokenManager::Consumer* consumer, OAuth2AccessTokenManager::Request* request) { - OAuth2AccessTokenConsumer::TokenResponse token_response = - OAuth2AccessTokenConsumer::TokenResponse("AccessToken", base::Time(), - "Idtoken"); - consumer->OnGetTokenSuccess(request, token_response); + consumer->OnGetTokenSuccess(request, TokenResponseBuilder() + .WithAccessToken("AccessToken") + .WithIdToken("Idtoken") + .build()); } void SimulateMergeSessionSuccess(GaiaAuthConsumer* consumer,
diff --git a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc index 8e3a33f..4063a0b6 100644 --- a/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc +++ b/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.cc
@@ -21,11 +21,11 @@ #include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/webdata/token_web_data.h" #include "components/webdata/common/web_data_service_base.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h" -#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "services/network/public/cpp/shared_url_loader_factory.h" namespace { @@ -300,8 +300,9 @@ } std::string refresh_token = GetRefreshToken(account_id); DCHECK(!refresh_token.empty()); - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory, refresh_token); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory, refresh_token); } GoogleServiceAuthError MutableProfileOAuth2TokenServiceDelegate::GetAuthError(
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service.cc index 804adebb..426f92c 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
@@ -23,6 +23,9 @@ using signin_metrics::SourceForRefreshTokenOperation; namespace { + +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + std::string SourceToString(SourceForRefreshTokenOperation source) { switch (source) { case SourceForRefreshTokenOperation::kUnknown: @@ -195,9 +198,10 @@ new OAuth2AccessTokenManager::RequestImpl(account_id, consumer)); // Create token response from token. Expiration time and id token do not // matter and should not be accessed. - OAuth2AccessTokenConsumer::TokenResponse token_response( - refresh_token, base::Time(), std::string()); - // If we can get refresh token from the delegate, inform consumer right away. + // TODO(1151018): See bug description for why the refresh token is passed + // in the access token field. + OAuth2AccessTokenConsumer::TokenResponse token_response = + TokenResponseBuilder().WithAccessToken(refresh_token).build(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&OAuth2AccessTokenManager::RequestImpl::InformConsumer,
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc index f7c4831b..2a43aaf 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.cc
@@ -29,6 +29,8 @@ namespace { +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + // Callback from FetchOAuth2TokenWithUsername(). // Arguments: // - the error, or NONE if the token fetch was successful. @@ -113,8 +115,10 @@ return; } if (error.state() == GoogleServiceAuthError::NONE) { - FireOnGetTokenSuccess(OAuth2AccessTokenConsumer::TokenResponse( - access_token, expiration_time, std::string())); + FireOnGetTokenSuccess(TokenResponseBuilder() + .WithAccessToken(access_token) + .WithExpirationTime(expiration_time) + .build()); } else { FireOnGetTokenFailure(error); }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.mm b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.mm index ea2e802..afa151d 100644 --- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.mm +++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.mm
@@ -30,6 +30,8 @@ namespace { +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + // Match the way Chromium handles authentication errors in // google_apis/gaia/oauth2_access_token_fetcher.cc: GoogleServiceAuthError GetGoogleServiceAuthErrorFromNSError( @@ -144,8 +146,10 @@ if (auth_error.state() == GoogleServiceAuthError::NONE) { base::Time expiration_date = base::Time::FromDoubleT([expiration timeIntervalSince1970]); - FireOnGetTokenSuccess(OAuth2AccessTokenConsumer::TokenResponse( - base::SysNSStringToUTF8(token), expiration_date, std::string())); + FireOnGetTokenSuccess(TokenResponseBuilder() + .WithAccessToken(base::SysNSStringToUTF8(token)) + .WithExpirationTime(expiration_date) + .build()); } else { FireOnGetTokenFailure(auth_error); }
diff --git a/components/signin/internal/identity_manager/ubertoken_fetcher_impl_unittest.cc b/components/signin/internal/identity_manager/ubertoken_fetcher_impl_unittest.cc index 94b8215..1009c62 100644 --- a/components/signin/internal/identity_manager/ubertoken_fetcher_impl_unittest.cc +++ b/components/signin/internal/identity_manager/ubertoken_fetcher_impl_unittest.cc
@@ -18,6 +18,8 @@ namespace { +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + const char kTestAccountId[] = "test@gmail.com"; class MockUbertokenConsumer { @@ -76,9 +78,8 @@ TEST_F(UbertokenFetcherImplTest, Basic) {} TEST_F(UbertokenFetcherImplTest, Success) { - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); fetcher_->OnUberAuthTokenSuccess("uberToken"); EXPECT_EQ(0, consumer_.nb_error_); @@ -105,9 +106,8 @@ TEST_F(UbertokenFetcherImplTest, TransientFailureEventualFailure) { GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED); - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); for (int i = 0; i < signin::UbertokenFetcherImpl::kMaxRetries; ++i) { fetcher_->OnUberAuthTokenFailure(error); @@ -124,9 +124,8 @@ TEST_F(UbertokenFetcherImplTest, TransientFailureEventualSuccess) { GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED); - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); for (int i = 0; i < signin::UbertokenFetcherImpl::kMaxRetries; ++i) { fetcher_->OnUberAuthTokenFailure(error); @@ -142,9 +141,8 @@ } TEST_F(UbertokenFetcherImplTest, PermanentFailureEventualFailure) { - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP); fetcher_->OnUberAuthTokenFailure(error); @@ -152,9 +150,9 @@ EXPECT_EQ(0, consumer_.nb_correct_token_); EXPECT_EQ("", consumer_.last_token_); - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); + fetcher_->OnUberAuthTokenFailure(error); EXPECT_EQ(1, consumer_.nb_error_); EXPECT_EQ(0, consumer_.nb_correct_token_); @@ -163,18 +161,18 @@ TEST_F(UbertokenFetcherImplTest, PermanentFailureEventualSuccess) { GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP); - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); fetcher_->OnUberAuthTokenFailure(error); EXPECT_EQ(0, consumer_.nb_error_); EXPECT_EQ(0, consumer_.nb_correct_token_); EXPECT_EQ("", consumer_.last_token_); - fetcher_->OnGetTokenSuccess(nullptr, - OAuth2AccessTokenConsumer::TokenResponse( - "accessToken", base::Time(), std::string())); + fetcher_->OnGetTokenSuccess( + nullptr, TokenResponseBuilder().WithAccessToken("accessToken").build()); + fetcher_->OnUberAuthTokenSuccess("uberToken"); EXPECT_EQ(0, consumer_.nb_error_); EXPECT_EQ(1, consumer_.nb_correct_token_);
diff --git a/components/signin/public/identity_manager/access_token_fetcher_unittest.cc b/components/signin/public/identity_manager/access_token_fetcher_unittest.cc index c541f24..5af56a6 100644 --- a/components/signin/public/identity_manager/access_token_fetcher_unittest.cc +++ b/components/signin/public/identity_manager/access_token_fetcher_unittest.cc
@@ -32,6 +32,8 @@ namespace { +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + const char kTestGaiaId[] = "dummyId"; const char kTestGaiaId2[] = "dummyId2"; const char kTestEmail[] = "me@gmail.com"; @@ -148,10 +150,11 @@ access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); } TEST_F(AccessTokenFetcherTest, @@ -178,10 +181,11 @@ access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); } TEST_F(AccessTokenFetcherTest, @@ -201,11 +205,14 @@ // Before the refresh token is available, the callback shouldn't get called. EXPECT_CALL(callback, Run(_, _)).Times(0); - token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + { + token_service()->IssueAllTokensForAccount( + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); + } // Once the refresh token becomes available, we should get an access token // request. @@ -218,11 +225,14 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); - token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + { + token_service()->IssueAllTokensForAccount( + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); + } } TEST_F(AccessTokenFetcherTest, @@ -269,10 +279,11 @@ // Now fulfilling the access token request should have no effect. token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); } TEST_F(AccessTokenFetcherTest, ReturnsErrorWhenAccountIsUnknown) { @@ -424,10 +435,11 @@ EXPECT_CALL(callback2, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); } TEST_F(AccessTokenFetcherTest, MultipleRequestsForDifferentAccountsFulfilled) { @@ -459,21 +471,28 @@ // called back with the access token. EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); - token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + { + token_service()->IssueAllTokensForAccount( + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); + } // Once the second access token request is fulfilled, it should get // called back with the access token. EXPECT_CALL(callback2, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); - token_service()->IssueAllTokensForAccount( - account_id2, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + { + token_service()->IssueAllTokensForAccount( + account_id2, + TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); + } } TEST_F(AccessTokenFetcherTest, @@ -525,10 +544,11 @@ Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())) .WillOnce(testing::InvokeWithoutArgs(&run_loop4, &base::RunLoop::Quit)); token_service()->IssueAllTokensForAccount( - account_id2, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id2, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); run_loop4.Run(); } @@ -566,12 +586,12 @@ // with the access token. EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); - token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); // Now add a second account and request an access token for it to test // that the default URLLoaderFactory is used if none is specified. @@ -605,10 +625,11 @@ EXPECT_CALL(callback2, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); token_service()->IssueAllTokensForAccount( - account_id2, - OAuth2AccessTokenConsumer::TokenResponse( - access_token_info().token, access_token_info().expiration_time, - access_token_info().id_token)); + account_id2, TokenResponseBuilder() + .WithAccessToken(access_token_info().token) + .WithExpirationTime(access_token_info().expiration_time) + .WithIdToken(access_token_info().id_token) + .build()); } } // namespace signin
diff --git a/components/signin/public/identity_manager/identity_test_environment.cc b/components/signin/public/identity_manager/identity_test_environment.cc index d56cbc2..aca7b97 100644 --- a/components/signin/public/identity_manager/identity_test_environment.cc +++ b/components/signin/public/identity_manager/identity_test_environment.cc
@@ -51,6 +51,8 @@ #include "components/signin/internal/identity_manager/accounts_mutator_impl.h" #endif +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + namespace signin { class IdentityManagerDependenciesOwner { @@ -476,7 +478,11 @@ const std::string& id_token) { WaitForAccessTokenRequestIfNecessary(base::nullopt); fake_token_service()->IssueTokenForAllPendingRequests( - OAuth2AccessTokenConsumer::TokenResponse(token, expiration, id_token)); + TokenResponseBuilder() + .WithAccessToken(token) + .WithExpirationTime(expiration) + .WithIdToken(id_token) + .build()); } void IdentityTestEnvironment:: @@ -487,8 +493,11 @@ const std::string& id_token) { WaitForAccessTokenRequestIfNecessary(account_id); fake_token_service()->IssueAllTokensForAccount( - account_id, - OAuth2AccessTokenConsumer::TokenResponse(token, expiration, id_token)); + account_id, TokenResponseBuilder() + .WithAccessToken(token) + .WithExpirationTime(expiration) + .WithIdToken(id_token) + .build()); } void IdentityTestEnvironment:: @@ -498,9 +507,12 @@ const std::string& id_token, const ScopeSet& scopes) { WaitForAccessTokenRequestIfNecessary(base::nullopt); - fake_token_service()->IssueTokenForScope( - scopes, - OAuth2AccessTokenConsumer::TokenResponse(token, expiration, id_token)); + fake_token_service()->IssueTokenForScope(scopes, + TokenResponseBuilder() + .WithAccessToken(token) + .WithExpirationTime(expiration) + .WithIdToken(id_token) + .build()); } void IdentityTestEnvironment::
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index fb8dc3637..6e8b16c 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -477,6 +477,7 @@ "protocol/proto_enum_conversions_unittest.cc", "protocol/proto_value_conversions_unittest.cc", "trusted_vault/download_keys_response_handler_unittest.cc", + "trusted_vault/proto_string_bytes_conversion_unittest.cc", "trusted_vault/securebox_unittest.cc", "trusted_vault/standalone_trusted_vault_backend_unittest.cc", "trusted_vault/trusted_vault_access_token_fetcher_frontend_unittest.cc",
diff --git a/components/sync/trusted_vault/BUILD.gn b/components/sync/trusted_vault/BUILD.gn index fb4341b..718d164 100644 --- a/components/sync/trusted_vault/BUILD.gn +++ b/components/sync/trusted_vault/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "download_keys_response_handler.cc", "download_keys_response_handler.h", + "proto_string_bytes_conversion.cc", + "proto_string_bytes_conversion.h", "securebox.cc", "securebox.h", "standalone_trusted_vault_backend.cc",
diff --git a/components/sync/trusted_vault/download_keys_response_handler.cc b/components/sync/trusted_vault/download_keys_response_handler.cc index b733635..ffc72ac 100644 --- a/components/sync/trusted_vault/download_keys_response_handler.cc +++ b/components/sync/trusted_vault/download_keys_response_handler.cc
@@ -8,6 +8,7 @@ #include <utility> #include "components/sync/protocol/vault.pb.h" +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" #include "crypto/hmac.h" @@ -71,20 +72,17 @@ const SecureBoxPrivateKey& member_private_key) { std::vector<ExtractedSharedKey> result; for (const sync_pb::SharedKey& shared_key : member.keys()) { - std::vector<uint8_t> wrapped_key(shared_key.wrapped_key().begin(), - shared_key.wrapped_key().end()); base::Optional<std::vector<uint8_t>> decrypted_key = - member_private_key.Decrypt(base::span<const uint8_t>(), - kWrappedKeyHeader, wrapped_key); + member_private_key.Decrypt( + base::span<const uint8_t>(), kWrappedKeyHeader, + /*encrypted_payload=*/ProtoStringToBytes(shared_key.wrapped_key())); if (!decrypted_key.has_value()) { // Decryption failed. return std::vector<ExtractedSharedKey>(); } - result.push_back( - ExtractedSharedKey{/*version=*/shared_key.epoch(), *decrypted_key, - /*key_proof=*/ - std::vector<uint8_t>(shared_key.key_proof().begin(), - shared_key.key_proof().end())}); + result.push_back(ExtractedSharedKey{ + /*version=*/shared_key.epoch(), *decrypted_key, + /*key_proof=*/ProtoStringToBytes(shared_key.key_proof())}); } std::sort(result.begin(), result.end(),
diff --git a/components/sync/trusted_vault/download_keys_response_handler_unittest.cc b/components/sync/trusted_vault/download_keys_response_handler_unittest.cc index 608fc17..6a1f229 100644 --- a/components/sync/trusted_vault/download_keys_response_handler_unittest.cc +++ b/components/sync/trusted_vault/download_keys_response_handler_unittest.cc
@@ -8,6 +8,7 @@ #include "base/strings/string_number_conversions.h" #include "components/sync/protocol/vault.pb.h" +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" #include "crypto/hmac.h" #include "testing/gmock/include/gmock/gmock.h" @@ -28,11 +29,6 @@ 'e', 'd', '_', 'k', 'e', 'y'}; const char kSecurityDomainName[] = "chromesync"; -void AssignBytesToProtoString(base::span<const uint8_t> bytes, - std::string* bytes_proto_field) { - *bytes_proto_field = std::string(bytes.begin(), bytes.end()); -} - std::unique_ptr<SecureBoxKeyPair> MakeTestKeyPair() { std::vector<uint8_t> private_key_bytes; bool success = base::HexStringToBytes(kEncodedPrivateKey, &private_key_bytes); @@ -50,7 +46,6 @@ DCHECK_EQ(trusted_vault_keys.size(), trusted_vault_keys_versions.size()); DCHECK_EQ(trusted_vault_keys.size(), signing_keys.size()); - std::vector<uint8_t> public_key_bytes = public_key.ExportToBytes(); AssignBytesToProtoString(public_key.ExportToBytes(), member->mutable_public_key());
diff --git a/components/sync/trusted_vault/proto_string_bytes_conversion.cc b/components/sync/trusted_vault/proto_string_bytes_conversion.cc new file mode 100644 index 0000000..d1d880f0 --- /dev/null +++ b/components/sync/trusted_vault/proto_string_bytes_conversion.cc
@@ -0,0 +1,18 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" + +namespace syncer { + +void AssignBytesToProtoString(base::span<const uint8_t> bytes, + std::string* bytes_proto_field) { + *bytes_proto_field = std::string(bytes.begin(), bytes.end()); +} + +std::vector<uint8_t> ProtoStringToBytes(const std::string& bytes_string) { + return std::vector<uint8_t>(bytes_string.begin(), bytes_string.end()); +} + +} // namespace syncer
diff --git a/components/sync/trusted_vault/proto_string_bytes_conversion.h b/components/sync/trusted_vault/proto_string_bytes_conversion.h new file mode 100644 index 0000000..a2accd4 --- /dev/null +++ b/components/sync/trusted_vault/proto_string_bytes_conversion.h
@@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SYNC_TRUSTED_VAULT_PROTO_STRING_BYTES_CONVERSION_H_ +#define COMPONENTS_SYNC_TRUSTED_VAULT_PROTO_STRING_BYTES_CONVERSION_H_ + +#include <string> +#include <vector> + +#include "base/containers/span.h" + +namespace syncer { + +// Helper function for filling protobuf bytes field: protobuf represent them as +// std::string, while in code std::vector<uint8_t> or base::span<uint8_t> is +// more common. +void AssignBytesToProtoString(base::span<const uint8_t> bytes, + std::string* bytes_proto_field); + +// Helper function for converting protobuf bytes fields (that are represented as +// std::string) to std::vector<uint8_t>, that is more convenient representation +// of bytes in the code. +std::vector<uint8_t> ProtoStringToBytes(const std::string& bytes_string); + +} // namespace syncer + +#endif // COMPONENTS_SYNC_TRUSTED_VAULT_PROTO_STRING_BYTES_CONVERSION_H_
diff --git a/components/sync/trusted_vault/proto_string_bytes_conversion_unittest.cc b/components/sync/trusted_vault/proto_string_bytes_conversion_unittest.cc new file mode 100644 index 0000000..cf05882 --- /dev/null +++ b/components/sync/trusted_vault/proto_string_bytes_conversion_unittest.cc
@@ -0,0 +1,30 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace syncer { + +namespace { + +using testing::ElementsAre; +using testing::Eq; + +TEST(ProtoStringBytesConversionTest, ShouldAssignBytesToProtoString) { + std::string proto_string; + AssignBytesToProtoString(std::vector<uint8_t>{65, 66, 67}, &proto_string); + EXPECT_THAT(proto_string, Eq("ABC")); +} + +TEST(ProtoStringBytesConversionTest, ShouldConvertProtoStringToBytes) { + const std::string proto_string = "ABC"; + EXPECT_THAT(ProtoStringToBytes(proto_string), ElementsAre(65, 66, 67)); +} + +} // namespace + +} // namespace syncer
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc index fa8ea11..d21743f 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -18,6 +18,7 @@ #include "components/os_crypt/os_crypt.h" #include "components/sync/base/time.h" #include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" namespace syncer { @@ -104,9 +105,9 @@ DCHECK(!ongoing_connection_request_); std::unique_ptr<SecureBoxKeyPair> key_pair = - SecureBoxKeyPair::CreateByPrivateKeyImport(base::as_bytes( - base::make_span(per_user_vault->local_device_registration_info() - .private_key_material()))); + SecureBoxKeyPair::CreateByPrivateKeyImport( + ProtoStringToBytes(per_user_vault->local_device_registration_info() + .private_key_material())); if (!key_pair) { // Corrupted state: device is registered, but |key_pair| can't be imported. // TODO(crbug.com/1094326): restore from this state (throw away the key and @@ -122,14 +123,12 @@ return; } - std::string last_key = per_user_vault->vault_key() - .at(per_user_vault->vault_key_size() - 1) - .key_material(); - std::vector<uint8_t> last_key_bytes(last_key.begin(), last_key.end()); // |this| outlives |connection_| and |ongoing_connection_request_|, so it's // safe to use base::Unretained() here. ongoing_connection_request_ = connection_->DownloadKeys( - *primary_account_, last_key_bytes, + *primary_account_, + /*last_trusted_vault_key=*/ + ProtoStringToBytes(per_user_vault->vault_key().rbegin()->key_material()), per_user_vault->last_vault_key_version(), std::move(key_pair), base::BindOnce(&StandaloneTrustedVaultBackend::OnKeysDownloaded, base::Unretained(this), account_info.gaia)); @@ -152,7 +151,8 @@ per_user_vault->set_keys_are_stale(false); per_user_vault->clear_vault_key(); for (const std::vector<uint8_t>& key : keys) { - per_user_vault->add_vault_key()->set_key_material(key.data(), key.size()); + AssignBytesToProtoString( + key, per_user_vault->add_vault_key()->mutable_key_material()); } WriteToDisk(data_, file_path_); @@ -265,9 +265,10 @@ std::unique_ptr<SecureBoxKeyPair> key_pair; if (per_user_vault->has_local_device_registration_info()) { - key_pair = SecureBoxKeyPair::CreateByPrivateKeyImport(base::as_bytes( - base::make_span(per_user_vault->local_device_registration_info() - .private_key_material()))); + key_pair = SecureBoxKeyPair::CreateByPrivateKeyImport( + /*private_key_bytes=*/ProtoStringToBytes( + per_user_vault->local_device_registration_info() + .private_key_material())); if (!key_pair) { // Device key is corrupted. // TODO(crbug.com/1102340): consider generation of new key in this case. @@ -280,26 +281,22 @@ // or registration callback is cancelled). To avoid duplicated registrations // device key is stored before sending the registration request, so the same // key will be used for future registration attempts. - std::vector<uint8_t> serialized_private_key = - key_pair->private_key().ExportToBytes(); - per_user_vault->mutable_local_device_registration_info() - ->set_private_key_material(serialized_private_key.data(), - serialized_private_key.size()); + AssignBytesToProtoString( + key_pair->private_key().ExportToBytes(), + per_user_vault->mutable_local_device_registration_info() + ->mutable_private_key_material()); WriteToDisk(data_, file_path_); } - std::string last_key = per_user_vault->vault_key() - .at(per_user_vault->vault_key_size() - 1) - .key_material(); - std::vector<uint8_t> last_key_bytes(last_key.begin(), last_key.end()); - // Cancel existing callbacks passed to |connection_| to ensure there is only // one ongoing request. AbandonConnectionRequest(); // |this| outlives |connection_| and |ongoing_connection_request_|, so it's // safe to use base::Unretained() here. ongoing_connection_request_ = connection_->RegisterAuthenticationFactor( - *primary_account_, last_key_bytes, + *primary_account_, + /*last_trusted_vault_key=*/ + ProtoStringToBytes(per_user_vault->vault_key().rbegin()->key_material()), per_user_vault->last_vault_key_version(), key_pair->public_key(), base::BindOnce(&StandaloneTrustedVaultBackend::OnDeviceRegistered, base::Unretained(this), gaia_id)); @@ -399,8 +396,7 @@ if (per_user_vault) { for (const sync_pb::LocalTrustedVaultKey& key : per_user_vault->vault_key()) { - const std::string& key_material = key.key_material(); - vault_keys.emplace_back(key_material.begin(), key_material.end()); + vault_keys.emplace_back(ProtoStringToBytes(key.key_material())); } }
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl.cc b/components/sync/trusted_vault/trusted_vault_connection_impl.cc index 15311fdc..2d4f4e3 100644 --- a/components/sync/trusted_vault/trusted_vault_connection_impl.cc +++ b/components/sync/trusted_vault/trusted_vault_connection_impl.cc
@@ -10,6 +10,7 @@ #include "components/signin/public/identity_manager/account_info.h" #include "components/sync/protocol/vault.pb.h" #include "components/sync/trusted_vault/download_keys_response_handler.h" +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" #include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" #include "components/sync/trusted_vault/trusted_vault_request.h" @@ -27,17 +28,6 @@ const char kListSecurityDomainsURLPathAndQuery[] = "/domain:list?view=1"; const char kSecurityDomainName[] = "chromesync"; -// Helper function for filling protobuf bytes field: protobuf represent them as -// std::string, while in code std::vector<uint8_t> or base::span<uint8_t> is -// more common. -// TODO(crbug.com/1113598): this function and its counterpart (proto string to -// bytes vector) is useful in many places under trusted_vault directory, -// consider moving it to some utility file. -void AssignBytesToProtoString(base::span<const uint8_t> bytes, - std::string* bytes_proto_field) { - *bytes_proto_field = std::string(bytes.begin(), bytes.end()); -} - void ProcessRegisterDeviceResponse( TrustedVaultConnection::RegisterAuthenticationFactorCallback callback, TrustedVaultRequest::HttpStatus http_status,
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc index a8023b0..edaea6c 100644 --- a/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc +++ b/components/sync/trusted_vault/trusted_vault_connection_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "components/signin/public/identity_manager/access_token_info.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/sync/protocol/vault.pb.h" +#include "components/sync/trusted_vault/proto_string_bytes_conversion.h" #include "components/sync/trusted_vault/securebox.h" #include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" @@ -169,21 +170,17 @@ ASSERT_THAT(security_domain.members(), SizeIs(1)); const sync_pb::SecurityDomain::Member& member = security_domain.members(0); - const std::vector<uint8_t> member_public_key_bytes( - member.public_key().begin(), member.public_key().end()); - EXPECT_THAT(member_public_key_bytes, + EXPECT_THAT(ProtoStringToBytes(member.public_key()), Eq(key_pair->public_key().ExportToBytes())); ASSERT_THAT(member.keys(), SizeIs(1)); const sync_pb::SharedKey& shared_key = member.keys(0); EXPECT_THAT(shared_key.epoch(), Eq(kLastKeyVersion)); - const std::vector<uint8_t> wrapped_key_bytes(shared_key.wrapped_key().begin(), - shared_key.wrapped_key().end()); base::Optional<std::vector<uint8_t>> decrypted_trusted_vault_key = key_pair->private_key().Decrypt( /*shared_key=*/base::span<const uint8_t>(), kWrappedKeyHeader, - /*encrypted_payload=*/wrapped_key_bytes); + /*encrypted_payload=*/ProtoStringToBytes(shared_key.wrapped_key())); ASSERT_THAT(decrypted_trusted_vault_key, Ne(base::nullopt)); EXPECT_THAT(*decrypted_trusted_vault_key, Eq(kTrustedVaultKey));
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc index 169259e..4b6a995 100644 --- a/content/browser/android/synchronous_compositor_host.cc +++ b/content/browser/android/synchronous_compositor_host.cc
@@ -103,11 +103,17 @@ void ReturnFrame( uint32_t layer_tree_frame_sink_id, uint32_t metadata_version, + const base::Optional<viz::LocalSurfaceId>& local_surface_id, base::Optional<viz::CompositorFrame> frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) override { - if (!bridge_->ReceiveFrameOnIOThread(layer_tree_frame_sink_id, - metadata_version, std::move(frame), - std::move(hit_test_region_list))) { + if (frame && (!local_surface_id || !local_surface_id->is_valid())) { + bad_message::ReceivedBadMessage( + process_id_, bad_message::SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID); + return; + } + if (!bridge_->ReceiveFrameOnIOThread( + layer_tree_frame_sink_id, metadata_version, local_surface_id, + std::move(frame), std::move(hit_test_region_list))) { bad_message::ReceivedBadMessage( process_id_, bad_message::SYNC_COMPOSITOR_NO_FUTURE_FRAME); } @@ -192,8 +198,7 @@ const gfx::Rect& viewport_rect_for_tile_priority, const gfx::Transform& transform_for_tile_priority) { invalidate_needs_draw_ = false; - scoped_refptr<FrameFuture> frame_future = - new FrameFuture(rwhva_->GetLocalSurfaceId()); + scoped_refptr<FrameFuture> frame_future = new FrameFuture(); if (!allow_async_draw_) { allow_async_draw_ = allow_async_draw_ || IsReadyForSynchronousCall(); auto frame_ptr = std::make_unique<Frame>(); @@ -227,6 +232,7 @@ transform_for_tile_priority); uint32_t layer_tree_frame_sink_id; uint32_t metadata_version = 0u; + base::Optional<viz::LocalSurfaceId> local_surface_id; base::Optional<viz::CompositorFrame> compositor_frame; base::Optional<viz::HitTestRegionList> hit_test_region_list; blink::mojom::SyncCompositorCommonRendererParamsPtr common_renderer_params; @@ -238,20 +244,30 @@ if (!IsReadyForSynchronousCall() || !GetSynchronousCompositor()->DemandDrawHw( std::move(params), &common_renderer_params, - &layer_tree_frame_sink_id, &metadata_version, &compositor_frame, - &hit_test_region_list)) { + &layer_tree_frame_sink_id, &metadata_version, &local_surface_id, + &compositor_frame, &hit_test_region_list)) { return SynchronousCompositor::Frame(); } } UpdateState(std::move(common_renderer_params)); - if (!compositor_frame) + if (compositor_frame) { + if (!local_surface_id || !local_surface_id->is_valid()) { + bad_message::ReceivedBadMessage( + rwhva_->GetRenderWidgetHost()->GetProcess()->GetID(), + bad_message::SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID); + return SynchronousCompositor::Frame(); + } + } else { return SynchronousCompositor::Frame(); + } SynchronousCompositor::Frame frame; frame.frame.reset(new viz::CompositorFrame); frame.layer_tree_frame_sink_id = layer_tree_frame_sink_id; + if (local_surface_id) + frame.local_surface_id = local_surface_id.value(); *frame.frame = std::move(*compositor_frame); frame.hit_test_region_list = std::move(hit_test_region_list); UpdateFrameMetaData(metadata_version, frame.frame->metadata.Clone());
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.cc b/content/browser/android/synchronous_compositor_sync_call_bridge.cc index cd94469..34fe0313 100644 --- a/content/browser/android/synchronous_compositor_sync_call_bridge.cc +++ b/content/browser/android/synchronous_compositor_sync_call_bridge.cc
@@ -40,6 +40,7 @@ bool SynchronousCompositorSyncCallBridge::ReceiveFrameOnIOThread( int layer_tree_frame_sink_id, uint32_t metadata_version, + base::Optional<viz::LocalSurfaceId> local_surface_id, base::Optional<viz::CompositorFrame> compositor_frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -54,6 +55,7 @@ frame_futures_.pop_front(); if (compositor_frame) { + DCHECK(local_surface_id); GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&SynchronousCompositorSyncCallBridge:: ProcessFrameMetadataOnUIThread, @@ -61,6 +63,7 @@ compositor_frame->metadata.Clone())); frame_ptr->frame.reset(new viz::CompositorFrame); *frame_ptr->frame = std::move(*compositor_frame); + frame_ptr->local_surface_id = local_surface_id.value(); frame_ptr->hit_test_region_list = std::move(hit_test_region_list); } future->SetFrame(std::move(frame_ptr));
diff --git a/content/browser/android/synchronous_compositor_sync_call_bridge.h b/content/browser/android/synchronous_compositor_sync_call_bridge.h index 262200f8..1699c750 100644 --- a/content/browser/android/synchronous_compositor_sync_call_bridge.h +++ b/content/browser/android/synchronous_compositor_sync_call_bridge.h
@@ -82,6 +82,7 @@ bool ReceiveFrameOnIOThread( int frame_sink_id, uint32_t metadata_version, + base::Optional<viz::LocalSurfaceId> local_surface_id, base::Optional<viz::CompositorFrame>, base::Optional<viz::HitTestRegionList> hit_test_region_list);
diff --git a/content/browser/background_fetch/storage/delete_registration_task.cc b/content/browser/background_fetch/storage/delete_registration_task.cc index d738ff2..d4a860a 100644 --- a/content/browser/background_fetch/storage/delete_registration_task.cc +++ b/content/browser/background_fetch/storage/delete_registration_task.cc
@@ -101,6 +101,7 @@ SetStorageError(BackgroundFetchStorageError::kServiceWorkerStorageError); AbandonFetches(service_worker_registration_id_); std::move(done_closure).Run(); + return; } } #endif // DCHECK_IS_ON()
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 95738c1..5f85aea 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -264,6 +264,7 @@ ASGH_ASSOCIATED_INTERFACE_REQUEST = 236, ASGH_RECEIVED_CONTROL_MESSAGE = 237, CSDH_BAD_OWNER = 238, + SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID = 239, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index fe8e036..7e81d9e 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -2335,8 +2335,13 @@ void ChildProcessSecurityPolicyImpl::AddOptInIsolatedOriginForBrowsingInstance( const IsolationContext& isolation_context, const url::Origin& origin) { - DCHECK(IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin)) - << "Attempting to opt-in invalid origin: " << origin; + if (!IsolatedOriginUtil::IsValidOriginForOptInIsolation(origin)) { + static auto* invalid_origin_optin_key = base::debug::AllocateCrashKeyString( + "invalid_opt_in_origin", base::debug::CrashKeySize::Size256); + base::debug::SetCrashKeyString(invalid_origin_optin_key, + origin.Serialize()); + base::debug::DumpWithoutCrashing(); + } BrowsingInstanceId browsing_instance_id( isolation_context.browsing_instance_id());
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 5da79c8..68b2d351 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8727,25 +8727,7 @@ // renderer one. The browser will just "push" the correct value. if (navigation_request->state() >= NavigationRequest::NavigationState::WILL_PROCESS_RESPONSE) { - if (params.sandbox_flags != navigation_request->SandboxFlagsToCommit()) { - DCHECK(false); - - base::debug::ScopedCrashKeyString scoped_url( - base::debug::AllocateCrashKeyString( - "url", base::debug::CrashKeySize::Size256), - params.url.possibly_invalid_spec()); - base::debug::ScopedCrashKeyString scoped_sandbox( - base::debug::AllocateCrashKeyString( - "sandbox", base::debug::CrashKeySize::Size256), - base::StringPrintf( - "%u, %u", uint32_t(params.sandbox_flags), - uint32_t(navigation_request->SandboxFlagsToCommit()))); - base::debug::SetCrashKeyString( - base::debug::AllocateCrashKeyString( - "is_main_frame", base::debug::CrashKeySize::Size32), - frame_tree_node_->IsMainFrame() ? "true" : "false"); - base::debug::DumpWithoutCrashing(); - } + DCHECK_EQ(params.sandbox_flags, navigation_request->SandboxFlagsToCommit()); } coep_reporter_ = navigation_request->TakeCoepReporter();
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index 1e4fa98..6cbf635 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -604,16 +604,27 @@ navigation_to_url2->ReadyToCommit(); TestRenderFrameHost* new_rfh = main_test_rfh(); - EXPECT_FALSE(contents()->CrossProcessNavigationPending()); - EXPECT_EQ(nullptr, contents()->GetPendingMainFrame()); - EXPECT_NE(orig_rfh, new_rfh); - EXPECT_EQ(orig_rvh_delete_count, 1); + if (ShouldSkipEarlyCommitPendingForCrashedFrame()) { + EXPECT_TRUE(contents()->CrossProcessNavigationPending()); + EXPECT_NE(nullptr, contents()->GetPendingMainFrame()); + EXPECT_EQ(orig_rfh, new_rfh); + EXPECT_EQ(orig_rvh_delete_count, 0); + } else { + EXPECT_FALSE(contents()->CrossProcessNavigationPending()); + EXPECT_EQ(nullptr, contents()->GetPendingMainFrame()); + EXPECT_NE(orig_rfh, new_rfh); + EXPECT_EQ(orig_rvh_delete_count, 1); + } navigation_to_url2->Commit(); SiteInstance* instance2 = contents()->GetSiteInstance(); EXPECT_FALSE(contents()->CrossProcessNavigationPending()); - EXPECT_EQ(new_rfh, main_rfh()); + if (ShouldSkipEarlyCommitPendingForCrashedFrame()) { + EXPECT_NE(new_rfh, main_rfh()); + } else { + EXPECT_EQ(new_rfh, main_rfh()); + } EXPECT_NE(instance1, instance2); EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
diff --git a/content/public/browser/android/synchronous_compositor.cc b/content/public/browser/android/synchronous_compositor.cc index 8d0b645..fd255be 100644 --- a/content/public/browser/android/synchronous_compositor.cc +++ b/content/public/browser/android/synchronous_compositor.cc
@@ -17,13 +17,12 @@ SynchronousCompositor::Frame::Frame(Frame&& rhs) : layer_tree_frame_sink_id(rhs.layer_tree_frame_sink_id), - frame(std::move(rhs.frame)) {} + frame(std::move(rhs.frame)), + local_surface_id(rhs.local_surface_id) {} -SynchronousCompositor::FrameFuture::FrameFuture( - viz::LocalSurfaceId local_surface_id) +SynchronousCompositor::FrameFuture::FrameFuture() : waitable_event_(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED), - local_surface_id_(local_surface_id) {} + base::WaitableEvent::InitialState::NOT_SIGNALED) {} SynchronousCompositor::FrameFuture::~FrameFuture() {} @@ -48,6 +47,7 @@ SynchronousCompositor::Frame& SynchronousCompositor::Frame::operator=( Frame&& rhs) { layer_tree_frame_sink_id = rhs.layer_tree_frame_sink_id; + local_surface_id = rhs.local_surface_id; frame = std::move(rhs.frame); return *this; }
diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h index 21a0280..4597208 100644 --- a/content/public/browser/android/synchronous_compositor.h +++ b/content/public/browser/android/synchronous_compositor.h
@@ -57,6 +57,8 @@ uint32_t layer_tree_frame_sink_id; std::unique_ptr<viz::CompositorFrame> frame; + // Invalid if |frame| is nullptr. + viz::LocalSurfaceId local_surface_id; base::Optional<viz::HitTestRegionList> hit_test_region_list; private: @@ -65,10 +67,9 @@ class FrameFuture : public base::RefCountedThreadSafe<FrameFuture> { public: - explicit FrameFuture(viz::LocalSurfaceId local_surface_id); + FrameFuture(); void SetFrame(std::unique_ptr<Frame> frame); std::unique_ptr<Frame> GetFrame(); - const viz::LocalSurfaceId& local_surface_id() { return local_surface_id_; } private: friend class base::RefCountedThreadSafe<FrameFuture>; @@ -76,7 +77,6 @@ base::WaitableEvent waitable_event_; std::unique_ptr<Frame> frame_; - viz::LocalSurfaceId local_surface_id_; #if DCHECK_IS_ON() bool waited_ = false; #endif
diff --git a/content/public/test/test_synchronous_compositor_android.cc b/content/public/test/test_synchronous_compositor_android.cc index 89b2001..d71da9c 100644 --- a/content/public/test/test_synchronous_compositor_android.cc +++ b/content/public/test/test_synchronous_compositor_android.cc
@@ -31,8 +31,7 @@ const gfx::Size& viewport_size, const gfx::Rect& viewport_rect_for_tile_priority, const gfx::Transform& transform_for_tile_priority) { - auto future = base::MakeRefCounted<FrameFuture>( - viz::LocalSurfaceId(1, base::UnguessableToken::Create())); + auto future = base::MakeRefCounted<FrameFuture>(); future->SetFrame(std::move(hardware_frame_)); return future; } @@ -61,6 +60,8 @@ std::unique_ptr<viz::CompositorFrame> frame) { hardware_frame_ = std::make_unique<Frame>(); hardware_frame_->layer_tree_frame_sink_id = layer_tree_frame_sink_id; + hardware_frame_->local_surface_id = + viz::LocalSurfaceId(1, base::UnguessableToken::Create()); hardware_frame_->frame = std::move(frame); }
diff --git a/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm b/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm index ad46a81a..afab6090 100644 --- a/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm +++ b/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm
@@ -145,7 +145,7 @@ void BluetoothLowEnergyDeviceWatcherMac::AddBluetoothPropertyListFileWatcher() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); property_list_watcher_->Watch( - BluetoothPlistFilePath(), false /* recursive */, + BluetoothPlistFilePath(), base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&BluetoothLowEnergyDeviceWatcherMac:: OnPropertyListFileChangedOnFileThread, this));
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc index afba13c4..2aee1db08 100644 --- a/gin/v8_platform.cc +++ b/gin/v8_platform.cc
@@ -258,7 +258,12 @@ Permission permissions) override { // If V8 sets permissions to none, we can discard the memory. if (permissions == v8::PageAllocator::Permission::kNoAccess) { - base::DecommitSystemPages(address, length, base::PageUpdatePermissions); + // Use PageKeepPermissionsIfPossible as an optimization, to avoid perf + // regression (see crrev.com/c/2563038 for details). This may cause the + // memory region to still be accessible on certain platforms, but at least + // the physical pages will be discarded. + base::DecommitSystemPages(address, length, + base::PageKeepPermissionsIfPossible); return true; } else { return base::TrySetSystemPagesAccess(address, length,
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn index d4d7509..bb74e013 100644 --- a/google_apis/BUILD.gn +++ b/google_apis/BUILD.gn
@@ -88,6 +88,8 @@ sources = [ "gaia/core_account_id.cc", "gaia/core_account_id.h", + "gaia/gaia_access_token_fetcher.cc", + "gaia/gaia_access_token_fetcher.h", "gaia/gaia_auth_consumer.cc", "gaia/gaia_auth_consumer.h", "gaia/gaia_auth_fetcher.cc",
diff --git a/google_apis/gaia/fake_oauth2_access_token_manager.cc b/google_apis/gaia/fake_oauth2_access_token_manager.cc index 1042bef5..3f3547f60 100644 --- a/google_apis/gaia/fake_oauth2_access_token_manager.cc +++ b/google_apis/gaia/fake_oauth2_access_token_manager.cc
@@ -12,19 +12,21 @@ #include "base/threading/thread_task_runner_handle.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -FakeOAuth2AccessTokenManager::PendingRequest::PendingRequest() {} +using TokenResponseBuilder = OAuth2AccessTokenConsumer::TokenResponse::Builder; + +FakeOAuth2AccessTokenManager::PendingRequest::PendingRequest() = default; FakeOAuth2AccessTokenManager::PendingRequest::PendingRequest( const PendingRequest& other) = default; -FakeOAuth2AccessTokenManager::PendingRequest::~PendingRequest() {} +FakeOAuth2AccessTokenManager::PendingRequest::~PendingRequest() = default; FakeOAuth2AccessTokenManager::FakeOAuth2AccessTokenManager( OAuth2AccessTokenManager::Delegate* delegate) : OAuth2AccessTokenManager(delegate), auto_post_fetch_response_on_message_loop_(false) {} -FakeOAuth2AccessTokenManager::~FakeOAuth2AccessTokenManager() {} +FakeOAuth2AccessTokenManager::~FakeOAuth2AccessTokenManager() = default; void FakeOAuth2AccessTokenManager::IssueAllTokensForAccount( const CoreAccountId& account_id, @@ -33,8 +35,10 @@ DCHECK(!auto_post_fetch_response_on_message_loop_); CompleteRequests(account_id, true, FakeOAuth2AccessTokenManager::ScopeSet(), GoogleServiceAuthError::AuthErrorNone(), - OAuth2AccessTokenConsumer::TokenResponse( - access_token, expiration, std::string() /* id_token */)); + TokenResponseBuilder() + .WithAccessToken(access_token) + .WithExpirationTime(expiration) + .build()); } void FakeOAuth2AccessTokenManager::IssueAllTokensForAccount( @@ -60,8 +64,10 @@ DCHECK(!auto_post_fetch_response_on_message_loop_); CompleteRequests(CoreAccountId(), false, scope, GoogleServiceAuthError::AuthErrorNone(), - OAuth2AccessTokenConsumer::TokenResponse( - access_token, expiration, std::string() /* id_token */)); + TokenResponseBuilder() + .WithAccessToken(access_token) + .WithExpirationTime(expiration) + .build()); } void FakeOAuth2AccessTokenManager::IssueTokenForScope( @@ -95,8 +101,10 @@ CompleteRequests(CoreAccountId(), true, FakeOAuth2AccessTokenManager::ScopeSet(), GoogleServiceAuthError::AuthErrorNone(), - OAuth2AccessTokenConsumer::TokenResponse( - access_token, expiration, std::string() /* id_token */)); + TokenResponseBuilder() + .WithAccessToken(access_token) + .WithExpirationTime(expiration) + .build()); } void FakeOAuth2AccessTokenManager::IssueTokenForAllPendingRequests( @@ -133,10 +141,7 @@ base::Time()); } - it->request->InformConsumer( - error, OAuth2AccessTokenConsumer::TokenResponse( - token_response.access_token, - token_response.expiration_time, token_response.id_token)); + it->request->InformConsumer(error, token_response); } } } @@ -190,8 +195,10 @@ weak_ptr_factory_.GetWeakPtr(), account_id, /*all_scoped=*/true, scopes, GoogleServiceAuthError::AuthErrorNone(), - OAuth2AccessTokenConsumer::TokenResponse( - "access_token", base::Time::Max(), std::string()))); + TokenResponseBuilder() + .WithAccessToken("access_token") + .WithExpirationTime(base::Time::Max()) + .build())); } }
diff --git a/google_apis/gaia/gaia_access_token_fetcher.cc b/google_apis/gaia/gaia_access_token_fetcher.cc new file mode 100644 index 0000000..fed71a7e --- /dev/null +++ b/google_apis/gaia/gaia_access_token_fetcher.cc
@@ -0,0 +1,93 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/gaia/gaia_access_token_fetcher.h" + +#include <string> + +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "google_apis/gaia/gaia_urls.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +// static +std::unique_ptr<GaiaAccessTokenFetcher> +GaiaAccessTokenFetcher::CreateExchangeRefreshTokenForAccessTokenInstance( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& refresh_token) { + // Using `new` to access a non-public constructor. + return base::WrapUnique(new GaiaAccessTokenFetcher( + consumer, url_loader_factory, refresh_token, std::string())); +} + +// static +std::unique_ptr<GaiaAccessTokenFetcher> +GaiaAccessTokenFetcher::CreateExchangeAuthCodeForRefeshTokenInstance( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& auth_code) { + // Using `new` to access a non-public constructor. + return base::WrapUnique(new GaiaAccessTokenFetcher( + consumer, url_loader_factory, std::string(), auth_code)); +} + +GaiaAccessTokenFetcher::GaiaAccessTokenFetcher( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& refresh_token, + const std::string& auth_code) + : OAuth2AccessTokenFetcherImpl(consumer, + url_loader_factory, + refresh_token, + auth_code) {} + +GaiaAccessTokenFetcher::~GaiaAccessTokenFetcher() = default; + +void GaiaAccessTokenFetcher::RecordResponseCodeUma(int error_value) const { + base::UmaHistogramSparse("Gaia.ResponseCodesForOAuth2AccessToken", + error_value); +} + +void GaiaAccessTokenFetcher::RecordBadRequestTypeUma( + OAuth2ErrorCodesForHistogram access_error) const { + UMA_HISTOGRAM_ENUMERATION("Gaia.BadRequestTypeForOAuth2AccessToken", + access_error, OAUTH2_ACCESS_ERROR_COUNT); +} + +GURL GaiaAccessTokenFetcher::GetAccessTokenURL() const { + return GaiaUrls::GetInstance()->oauth2_token_url(); +} + +net::NetworkTrafficAnnotationTag +GaiaAccessTokenFetcher::GetTrafficAnnotationTag() const { + return net::DefineNetworkTrafficAnnotation("oauth2_access_token_fetcher", R"( + semantics { + sender: "OAuth 2.0 Access Token Fetcher" + description: + "This request is used by the Token Service to fetch an OAuth 2.0 " + "access token for a known Google account." + trigger: + "This request can be triggered at any moment when any service " + "requests an OAuth 2.0 access token from the Token Service." + data: + "Chrome OAuth 2.0 client id and secret, the set of OAuth 2.0 " + "scopes and the OAuth 2.0 refresh token." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled in settings, but if user signs " + "out of Chrome, this request would not be made." + chrome_policy { + SigninAllowed { + policy_options {mode: MANDATORY} + SigninAllowed: false + } + } + })"); +}
diff --git a/google_apis/gaia/gaia_access_token_fetcher.h b/google_apis/gaia/gaia_access_token_fetcher.h new file mode 100644 index 0000000..4ec0b87f --- /dev/null +++ b/google_apis/gaia/gaia_access_token_fetcher.h
@@ -0,0 +1,54 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GOOGLE_APIS_GAIA_GAIA_ACCESS_TOKEN_FETCHER_H_ +#define GOOGLE_APIS_GAIA_GAIA_ACCESS_TOKEN_FETCHER_H_ + +#include <memory> +#include <string> + +#include "base/memory/ref_counted.h" +#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" + +class OAuth2AccessTokenConsumer; + +namespace network { +class SharedURLLoaderFactory; +} + +// An implementation of OAuth2AccessTokenFetcherImpl for retrieving OAuth2 +// tokens from Google's authorization server. See "Refreshing an access token" +// for more Google specific info: +// https://developers.google.com/identity/protocols/oauth2/web-server?csw=1#obtainingaccesstokens +class GaiaAccessTokenFetcher : public OAuth2AccessTokenFetcherImpl { + public: + static std::unique_ptr<GaiaAccessTokenFetcher> + CreateExchangeRefreshTokenForAccessTokenInstance( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& refresh_token); + static std::unique_ptr<GaiaAccessTokenFetcher> + CreateExchangeAuthCodeForRefeshTokenInstance( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& auth_code); + + ~GaiaAccessTokenFetcher() override; + + private: + GaiaAccessTokenFetcher( + OAuth2AccessTokenConsumer* consumer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& refresh_token, + const std::string& auth_code); + + // OAuth2AccessTokenFetcherImpl: + void RecordResponseCodeUma(int error_value) const override; + void RecordBadRequestTypeUma( + OAuth2ErrorCodesForHistogram access_error) const override; + GURL GetAccessTokenURL() const override; + net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() const override; +}; + +#endif // GOOGLE_APIS_GAIA_GAIA_ACCESS_TOKEN_FETCHER_H_
diff --git a/google_apis/gaia/oauth2_access_token_consumer.cc b/google_apis/gaia/oauth2_access_token_consumer.cc index 47343596..db7c8466 100644 --- a/google_apis/gaia/oauth2_access_token_consumer.cc +++ b/google_apis/gaia/oauth2_access_token_consumer.cc
@@ -4,18 +4,76 @@ #include "google_apis/gaia/oauth2_access_token_consumer.h" +OAuth2AccessTokenConsumer::TokenResponse::TokenResponse() = default; + +OAuth2AccessTokenConsumer::TokenResponse::TokenResponse(const TokenResponse&) = + default; + +OAuth2AccessTokenConsumer::TokenResponse::TokenResponse(TokenResponse&&) = + default; + OAuth2AccessTokenConsumer::TokenResponse::TokenResponse( const std::string& access_token, + const std::string& refresh_token, const base::Time& expiration_time, const std::string& id_token) : access_token(access_token), + refresh_token(refresh_token), expiration_time(expiration_time), id_token(id_token) {} -OAuth2AccessTokenConsumer::~OAuth2AccessTokenConsumer() {} +OAuth2AccessTokenConsumer::TokenResponse::~TokenResponse() = default; + +OAuth2AccessTokenConsumer::TokenResponse& +OAuth2AccessTokenConsumer::TokenResponse::operator=( + const TokenResponse& response) = default; + +OAuth2AccessTokenConsumer::TokenResponse& +OAuth2AccessTokenConsumer::TokenResponse::operator=(TokenResponse&& response) = + default; + +OAuth2AccessTokenConsumer::TokenResponse::Builder::Builder() = default; + +OAuth2AccessTokenConsumer::TokenResponse::Builder::~Builder() = default; + +OAuth2AccessTokenConsumer::TokenResponse::Builder& +OAuth2AccessTokenConsumer::TokenResponse::Builder::WithAccessToken( + const std::string& access_token) { + access_token_ = access_token; + return *this; +} + +OAuth2AccessTokenConsumer::TokenResponse::Builder& +OAuth2AccessTokenConsumer::TokenResponse::Builder::WithRefreshToken( + const std::string& refresh_token) { + refresh_token_ = refresh_token; + return *this; +} + +OAuth2AccessTokenConsumer::TokenResponse::Builder& +OAuth2AccessTokenConsumer::TokenResponse::Builder::WithExpirationTime( + const base::Time& expiration_time) { + expiration_time_ = expiration_time; + return *this; +} + +OAuth2AccessTokenConsumer::TokenResponse::Builder& +OAuth2AccessTokenConsumer::TokenResponse::Builder::WithIdToken( + const std::string& id_token) { + id_token_ = id_token; + return *this; +} + +OAuth2AccessTokenConsumer::TokenResponse +OAuth2AccessTokenConsumer::TokenResponse::Builder::build() { + return TokenResponse(access_token_, refresh_token_, expiration_time_, + id_token_); +} + +OAuth2AccessTokenConsumer::~OAuth2AccessTokenConsumer() = default; void OAuth2AccessTokenConsumer::OnGetTokenSuccess( const TokenResponse& token_response) {} void OAuth2AccessTokenConsumer::OnGetTokenFailure( - const GoogleServiceAuthError& error) {} \ No newline at end of file + const GoogleServiceAuthError& error) {}
diff --git a/google_apis/gaia/oauth2_access_token_consumer.h b/google_apis/gaia/oauth2_access_token_consumer.h index bc23ba9..da788f1 100644 --- a/google_apis/gaia/oauth2_access_token_consumer.h +++ b/google_apis/gaia/oauth2_access_token_consumer.h
@@ -18,14 +18,19 @@ public: // Structure representing information contained in OAuth2 access token. struct TokenResponse { - TokenResponse() = default; - TokenResponse(const std::string& access_token, - const base::Time& expiration_time, - const std::string& id_token); + TokenResponse(); + TokenResponse(const TokenResponse& response); + TokenResponse(TokenResponse&& response); + ~TokenResponse(); + TokenResponse& operator=(const TokenResponse& response); + TokenResponse& operator=(TokenResponse&& response); // OAuth2 access token. std::string access_token; + // OAuth2 refresh token. May be empty. + std::string refresh_token; + // The date until which the |access_token| can be used. // This value has a built-in safety margin, so it can be used as-is. base::Time expiration_time; @@ -33,6 +38,35 @@ // Contains extra information regarding the user's currently registered // services. std::string id_token; + + // Helper class to make building TokenResponse objects clearer. + class Builder { + public: + Builder(); + ~Builder(); + + Builder& WithAccessToken(const std::string& access_token); + Builder& WithRefreshToken(const std::string& refresh_token); + Builder& WithExpirationTime(const base::Time& expiration_time); + Builder& WithIdToken(const std::string& id_token); + + TokenResponse build(); + + private: + std::string access_token_; + std::string refresh_token_; + base::Time expiration_time_; + std::string id_token_; + }; + + private: + friend class Builder; + friend class OAuth2AccessTokenConsumer; + + TokenResponse(const std::string& access_token, + const std::string& refresh_token, + const base::Time& expiration_time, + const std::string& id_token); }; OAuth2AccessTokenConsumer() = default;
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc index dd780608..d407f73 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl.cc +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
@@ -10,19 +10,14 @@ #include "base/bind.h" #include "base/json/json_reader.h" -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "base/values.h" #include "google_apis/gaia/gaia_auth_util.h" -#include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/base/escape.h" #include "net/http/http_status_code.h" -#include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/simple_url_loader.h" @@ -31,90 +26,58 @@ constexpr char kGetAccessTokenBodyFormat[] = "client_id=%s&" "client_secret=%s&" - "grant_type=refresh_token&" - "refresh_token=%s"; + "grant_type=%s&" + "%s=%s"; constexpr char kGetAccessTokenBodyWithScopeFormat[] = "client_id=%s&" "client_secret=%s&" - "grant_type=refresh_token&" - "refresh_token=%s&" + "grant_type=%s&" + "%s=%s&" "scope=%s"; +constexpr char kGrantTypeAuthCode[] = "authorization_code"; +constexpr char kGrantTypeRefreshToken[] = "refresh_token"; + +constexpr char kKeyAuthCode[] = "code"; +constexpr char kKeyRefreshToken[] = "refresh_token"; + constexpr char kAccessTokenKey[] = "access_token"; +constexpr char krefreshTokenKey[] = "refresh_token"; constexpr char kExpiresInKey[] = "expires_in"; constexpr char kIdTokenKey[] = "id_token"; constexpr char kErrorKey[] = "error"; -// Enumerated constants for logging server responses on 400 errors, matching -// RFC 6749. -enum OAuth2ErrorCodesForHistogram { - OAUTH2_ACCESS_ERROR_INVALID_REQUEST = 0, - OAUTH2_ACCESS_ERROR_INVALID_CLIENT, - OAUTH2_ACCESS_ERROR_INVALID_GRANT, - OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT, - OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE, - OAUTH2_ACCESS_ERROR_INVALID_SCOPE, - OAUTH2_ACCESS_ERROR_UNKNOWN, - OAUTH2_ACCESS_ERROR_COUNT -}; - -OAuth2ErrorCodesForHistogram OAuth2ErrorToHistogramValue( - const std::string& error) { +OAuth2AccessTokenFetcherImpl::OAuth2ErrorCodesForHistogram +OAuth2ErrorToHistogramValue(const std::string& error) { if (error == "invalid_request") - return OAUTH2_ACCESS_ERROR_INVALID_REQUEST; + return OAuth2AccessTokenFetcherImpl::OAUTH2_ACCESS_ERROR_INVALID_REQUEST; else if (error == "invalid_client") - return OAUTH2_ACCESS_ERROR_INVALID_CLIENT; + return OAuth2AccessTokenFetcherImpl::OAUTH2_ACCESS_ERROR_INVALID_CLIENT; else if (error == "invalid_grant") - return OAUTH2_ACCESS_ERROR_INVALID_GRANT; + return OAuth2AccessTokenFetcherImpl::OAUTH2_ACCESS_ERROR_INVALID_GRANT; else if (error == "unauthorized_client") - return OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT; + return OAuth2AccessTokenFetcherImpl:: + OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT; else if (error == "unsupported_grant_type") - return OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE; + return OAuth2AccessTokenFetcherImpl:: + OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE; else if (error == "invalid_scope") - return OAUTH2_ACCESS_ERROR_INVALID_SCOPE; + return OAuth2AccessTokenFetcherImpl::OAUTH2_ACCESS_ERROR_INVALID_SCOPE; - return OAUTH2_ACCESS_ERROR_UNKNOWN; + return OAuth2AccessTokenFetcherImpl::OAUTH2_ACCESS_ERROR_UNKNOWN; } static GoogleServiceAuthError CreateAuthError(int net_error) { CHECK_NE(net_error, net::OK); - DLOG(WARNING) << "Could not reach Google Accounts servers: errno " - << net_error; + DLOG(WARNING) << "Could not reach Authorization servers: errno " << net_error; return GoogleServiceAuthError::FromConnectionError(net_error); } static std::unique_ptr<network::SimpleURLLoader> CreateURLLoader( const GURL& url, - const std::string& body) { - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("oauth2_access_token_fetcher", R"( - semantics { - sender: "OAuth 2.0 Access Token Fetcher" - description: - "This request is used by the Token Service to fetch an OAuth 2.0 " - "access token for a known Google account." - trigger: - "This request can be triggered at any moment when any service " - "requests an OAuth 2.0 access token from the Token Service." - data: - "Chrome OAuth 2.0 client id and secret, the set of OAuth 2.0 " - "scopes and the OAuth 2.0 refresh token." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: NO - setting: - "This feature cannot be disabled in settings, but if user signs " - "out of Chrome, this request would not be made." - chrome_policy { - SigninAllowed { - policy_options {mode: MANDATORY} - SigninAllowed: false - } - } - })"); - + const std::string& body, + const net::NetworkTrafficAnnotationTag& traffic_annotation) { auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = url; resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; @@ -160,13 +123,19 @@ OAuth2AccessTokenFetcherImpl::OAuth2AccessTokenFetcherImpl( OAuth2AccessTokenConsumer* consumer, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& refresh_token) + const std::string& refresh_token, + const std::string& auth_code) : OAuth2AccessTokenFetcher(consumer), url_loader_factory_(url_loader_factory), refresh_token_(refresh_token), - state_(INITIAL) {} + auth_code_(auth_code), + state_(INITIAL) { + // It's an error to specify neither a refresh token nor an auth code, or + // to specify both at the same time. + CHECK_NE(refresh_token_.empty(), auth_code_.empty()); +} -OAuth2AccessTokenFetcherImpl::~OAuth2AccessTokenFetcherImpl() {} +OAuth2AccessTokenFetcherImpl::~OAuth2AccessTokenFetcherImpl() = default; void OAuth2AccessTokenFetcherImpl::CancelRequest() { url_loader_.reset(); @@ -185,10 +154,11 @@ void OAuth2AccessTokenFetcherImpl::StartGetAccessToken() { CHECK_EQ(INITIAL, state_); state_ = GET_ACCESS_TOKEN_STARTED; - url_loader_ = - CreateURLLoader(MakeGetAccessTokenUrl(), - MakeGetAccessTokenBody(client_id_, client_secret_, - refresh_token_, scopes_)); + url_loader_ = CreateURLLoader( + GetAccessTokenURL(), + MakeGetAccessTokenBody(client_id_, client_secret_, refresh_token_, + auth_code_, scopes_), + GetTrafficAnnotationTag()); // It's safe to use Unretained below as the |url_loader_| is owned by |this|. url_loader_->DownloadToString( url_loader_factory_.get(), @@ -211,8 +181,8 @@ histogram_value = url_loader_->NetError(); net_failure = true; } - base::UmaHistogramSparse("Gaia.ResponseCodesForOAuth2AccessToken", - histogram_value); + RecordResponseCodeUma(histogram_value); + if (net_failure) { OnGetTokenFailure(CreateAuthError(histogram_value)); return; @@ -238,19 +208,17 @@ case net::HTTP_BAD_REQUEST: { // HTTP_BAD_REQUEST (400) usually contains error as per // http://tools.ietf.org/html/rfc6749#section-5.2. - std::string gaia_error; + std::string oauth2_error; if (!ParseGetAccessTokenFailureResponse(std::move(response_body), - &gaia_error)) { + &oauth2_error)) { OnGetTokenFailure( GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR)); return; } OAuth2ErrorCodesForHistogram access_error( - OAuth2ErrorToHistogramValue(gaia_error)); - UMA_HISTOGRAM_ENUMERATION("Gaia.BadRequestTypeForOAuth2AccessToken", - access_error, - OAUTH2_ACCESS_ERROR_COUNT); + OAuth2ErrorToHistogramValue(oauth2_error)); + RecordBadRequestTypeUma(access_error); OnGetTokenFailure( access_error == OAUTH2_ACCESS_ERROR_INVALID_GRANT @@ -280,11 +248,9 @@ // The request was successfully fetched and it returned OK. // Parse out the access token and the expiration time. - std::string access_token; - int expires_in; - std::string id_token; - if (!ParseGetAccessTokenSuccessResponse( - std::move(response_body), &access_token, &expires_in, &id_token)) { + OAuth2AccessTokenConsumer::TokenResponse token_response; + if (!ParseGetAccessTokenSuccessResponse(std::move(response_body), + &token_response)) { DLOG(WARNING) << "Response doesn't match expected format"; OnGetTokenFailure( GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); @@ -292,10 +258,7 @@ } // The token will expire in |expires_in| seconds. Take a 10% error margin to // prevent reusing a token too close to its expiration date. - OnGetTokenSuccess(OAuth2AccessTokenConsumer::TokenResponse( - access_token, - base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10), - id_token)); + OnGetTokenSuccess(token_response); } void OAuth2AccessTokenFetcherImpl::OnGetTokenSuccess( @@ -316,33 +279,42 @@ } // static -GURL OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenUrl() { - return GaiaUrls::GetInstance()->oauth2_token_url(); -} - -// static std::string OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenBody( const std::string& client_id, const std::string& client_secret, const std::string& refresh_token, + const std::string& auth_code, const std::vector<std::string>& scopes) { + // It's an error to specify neither a refresh token nor an auth code, or + // to specify both at the same time. + CHECK_NE(refresh_token.empty(), auth_code.empty()); + std::string enc_client_id = net::EscapeUrlEncodedData(client_id, true); std::string enc_client_secret = net::EscapeUrlEncodedData(client_secret, true); - std::string enc_refresh_token = - net::EscapeUrlEncodedData(refresh_token, true); + + const char* key = nullptr; + const char* grant_type = nullptr; + std::string enc_value; + if (refresh_token.empty()) { + key = kKeyAuthCode; + grant_type = kGrantTypeAuthCode; + enc_value = net::EscapeUrlEncodedData(auth_code, true); + } else { + key = kKeyRefreshToken; + grant_type = kGrantTypeRefreshToken; + enc_value = net::EscapeUrlEncodedData(refresh_token, true); + } + if (scopes.empty()) { - return base::StringPrintf(kGetAccessTokenBodyFormat, - enc_client_id.c_str(), - enc_client_secret.c_str(), - enc_refresh_token.c_str()); + return base::StringPrintf(kGetAccessTokenBodyFormat, enc_client_id.c_str(), + enc_client_secret.c_str(), grant_type, key, + enc_value.c_str()); } else { std::string scopes_string = base::JoinString(scopes, " "); return base::StringPrintf( - kGetAccessTokenBodyWithScopeFormat, - enc_client_id.c_str(), - enc_client_secret.c_str(), - enc_refresh_token.c_str(), + kGetAccessTokenBodyWithScopeFormat, enc_client_id.c_str(), + enc_client_secret.c_str(), grant_type, key, enc_value.c_str(), net::EscapeUrlEncodedData(scopes_string, true).c_str()); } } @@ -350,18 +322,25 @@ // static bool OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( std::unique_ptr<std::string> response_body, - std::string* access_token, - int* expires_in, - std::string* id_token) { - CHECK(access_token); + OAuth2AccessTokenConsumer::TokenResponse* token_response) { + CHECK(token_response); std::unique_ptr<base::DictionaryValue> value = ParseGetAccessTokenResponse(std::move(response_body)); if (!value) return false; - // ID token field is optional. - value->GetString(kIdTokenKey, id_token); - return value->GetString(kAccessTokenKey, access_token) && - value->GetInteger(kExpiresInKey, expires_in); + + // Refresh and id token are optional and don't cause an error if missing. + value->GetString(krefreshTokenKey, &token_response->refresh_token); + value->GetString(kIdTokenKey, &token_response->id_token); + + int expires_in; + bool ok = value->GetString(kAccessTokenKey, &token_response->access_token) && + value->GetInteger(kExpiresInKey, &expires_in); + if (ok) { + token_response->expiration_time = + base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10); + } + return ok; } // static
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl.h b/google_apis/gaia/oauth2_access_token_fetcher_impl.h index 6bf897d..07b5e17 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl.h +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl.h
@@ -14,6 +14,7 @@ #include "base/memory/ref_counted.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" #include "google_apis/gaia/oauth2_access_token_fetcher.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" class OAuth2AccessTokenFetcherImplTest; @@ -24,13 +25,11 @@ } // Abstracts the details to get OAuth2 access token from OAuth2 refresh token. -// See "Using the Refresh Token" section in: -// http://code.google.com/apis/accounts/docs/OAuth2WebServer.html +// See general document about Oauth2 in https://tools.ietf.org/html/rfc6749. // // This class should be used on a single thread, but it can be whichever thread -// that you like. -// Also, do not reuse the same instance. Once Start() is called, the instance -// should not be reused. +// that you like. Also, do not reuse the same instance. Once Start() is called, +// the instance should not be reused. // // Usage: // * Create an instance with a consumer. @@ -39,13 +38,28 @@ // thread Start was called with the results. // // This class can handle one request at a time. To parallelize requests, -// create multiple instances. +// create multiple instances. Prefer `GaiaAccessTokenFetcher` over this class +// while talking to Google's OAuth servers. class OAuth2AccessTokenFetcherImpl : public OAuth2AccessTokenFetcher { public: + // Enumerated constants for logging server responses on 400 errors, matching + // RFC 6749. + enum OAuth2ErrorCodesForHistogram { + OAUTH2_ACCESS_ERROR_INVALID_REQUEST = 0, + OAUTH2_ACCESS_ERROR_INVALID_CLIENT, + OAUTH2_ACCESS_ERROR_INVALID_GRANT, + OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT, + OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE, + OAUTH2_ACCESS_ERROR_INVALID_SCOPE, + OAUTH2_ACCESS_ERROR_UNKNOWN, + OAUTH2_ACCESS_ERROR_COUNT, + }; + OAuth2AccessTokenFetcherImpl( OAuth2AccessTokenConsumer* consumer, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& refresh_token); + const std::string& refresh_token, + const std::string& auth_code = std::string()); ~OAuth2AccessTokenFetcherImpl() override; // Implementation of OAuth2AccessTokenFetcher @@ -63,6 +77,17 @@ ERROR_STATE, }; + // Derived classes override these methods to record UMA histograms if needed. + virtual void RecordResponseCodeUma(int error_value) const {} + virtual void RecordBadRequestTypeUma( + OAuth2ErrorCodesForHistogram access_error) const {} + + // Derived class must specify the GetAccessToken base URL to use. + virtual GURL GetAccessTokenURL() const = 0; + + // Derived classes must specify a network annotation for the fetcher. + virtual net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() const = 0; + void OnURLLoadComplete(std::unique_ptr<std::string> response_body); // Helper methods for the flow. @@ -74,19 +99,16 @@ const OAuth2AccessTokenConsumer::TokenResponse& token_response); void OnGetTokenFailure(const GoogleServiceAuthError& error); - // Other helpers. - static GURL MakeGetAccessTokenUrl(); static std::string MakeGetAccessTokenBody( const std::string& client_id, const std::string& client_secret, const std::string& refresh_token, + const std::string& auth_code, const std::vector<std::string>& scopes); static bool ParseGetAccessTokenSuccessResponse( std::unique_ptr<std::string> response_body, - std::string* access_token, - int* expires_in, - std::string* id_token); + OAuth2AccessTokenConsumer::TokenResponse* token_response); static bool ParseGetAccessTokenFailureResponse( std::unique_ptr<std::string> response_body, @@ -95,6 +117,7 @@ // State that is set during construction. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; const std::string refresh_token_; + const std::string auth_code_; State state_; // While a fetch is in progress.
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc index 4d1ce69..2380e5d 100644 --- a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc +++ b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
@@ -12,6 +12,8 @@ #include "base/bind.h" #include "base/run_loop.h" #include "base/test/task_environment.h" +#include "base/time/time.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" @@ -74,9 +76,11 @@ class OAuth2AccessTokenFetcherImplTest : public testing::Test { public: OAuth2AccessTokenFetcherImplTest() - : fetcher_(&consumer_, - url_loader_factory_.GetSafeWeakWrapper(), - "refresh_token") { + : fetcher_(GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + &consumer_, + url_loader_factory_.GetSafeWeakWrapper(), + "refresh_token")) { url_loader_factory_.SetInterceptor(base::BindRepeating( &URLLoaderFactoryInterceptor::Intercept, base::Unretained(&url_loader_factory_interceptor_))); @@ -118,21 +122,21 @@ MockOAuth2AccessTokenConsumer consumer_; URLLoaderFactoryInterceptor url_loader_factory_interceptor_; network::TestURLLoaderFactory url_loader_factory_; - OAuth2AccessTokenFetcherImpl fetcher_; + std::unique_ptr<GaiaAccessTokenFetcher> fetcher_; }; // These four tests time out, see http://crbug.com/113446. TEST_F(OAuth2AccessTokenFetcherImplTest, GetAccessTokenRequestFailure) { SetupGetAccessToken(net::ERR_FAILED, net::HTTP_OK, std::string()); EXPECT_CALL(consumer_, OnGetTokenFailure(_)).Times(1); - fetcher_.Start("client_id", "client_secret", ScopeList()); + fetcher_->Start("client_id", "client_secret", ScopeList()); base::RunLoop().RunUntilIdle(); } TEST_F(OAuth2AccessTokenFetcherImplTest, GetAccessTokenResponseCodeFailure) { SetupGetAccessToken(net::OK, net::HTTP_FORBIDDEN, std::string()); EXPECT_CALL(consumer_, OnGetTokenFailure(_)).Times(1); - fetcher_.Start("client_id", "client_secret", ScopeList()); + fetcher_->Start("client_id", "client_secret", ScopeList()); base::RunLoop().RunUntilIdle(); } @@ -144,14 +148,14 @@ ASSERT_TRUE(expected_error.IsTransientError()); SetupProxyError(); EXPECT_CALL(consumer_, OnGetTokenFailure(expected_error)).Times(1); - fetcher_.Start("client_id", "client_secret", ScopeList()); + fetcher_->Start("client_id", "client_secret", ScopeList()); base::RunLoop().RunUntilIdle(); } TEST_F(OAuth2AccessTokenFetcherImplTest, Success) { SetupGetAccessToken(net::OK, net::HTTP_OK, kValidTokenResponse); EXPECT_CALL(consumer_, OnGetTokenSuccess(_)).Times(1); - fetcher_.Start("client_id", "client_secret", ScopeList()); + fetcher_->Start("client_id", "client_secret", ScopeList()); base::RunLoop().RunUntilIdle(); } @@ -162,7 +166,7 @@ "grant_type=refresh_token&" "refresh_token=rt1"; EXPECT_EQ(body, OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenBody( - "cid1", "cs1", "rt1", ScopeList())); + "cid1", "cs1", "rt1", std::string(), ScopeList())); } TEST_F(OAuth2AccessTokenFetcherImplTest, MakeGetAccessTokenBodyOneScope) { @@ -174,7 +178,7 @@ "scope=https://www.googleapis.com/foo"; ScopeList scopes = {"https://www.googleapis.com/foo"}; EXPECT_EQ(body, OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenBody( - "cid1", "cs1", "rt1", scopes)); + "cid1", "cs1", "rt1", std::string(), scopes)); } TEST_F(OAuth2AccessTokenFetcherImplTest, MakeGetAccessTokenBodyMultipleScopes) { @@ -190,49 +194,43 @@ "https://www.googleapis.com/bar", "https://www.googleapis.com/baz"}; EXPECT_EQ(body, OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenBody( - "cid1", "cs1", "rt1", scopes)); + "cid1", "cs1", "rt1", std::string(), scopes)); } TEST_F(OAuth2AccessTokenFetcherImplTest, ParseGetAccessTokenResponseNoBody) { - std::string at; - int expires_in; - std::string id_token; + OAuth2AccessTokenConsumer::TokenResponse token_response; auto empty_body = std::make_unique<std::string>(""); EXPECT_FALSE(OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( - std::move(empty_body), &at, &expires_in, &id_token)); - EXPECT_TRUE(at.empty()); + std::move(empty_body), &token_response)); + EXPECT_TRUE(token_response.access_token.empty()); } TEST_F(OAuth2AccessTokenFetcherImplTest, ParseGetAccessTokenResponseBadJson) { - std::string at; - int expires_in; - std::string id_token; + OAuth2AccessTokenConsumer::TokenResponse token_response; EXPECT_FALSE(OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( - std::make_unique<std::string>("foo"), &at, &expires_in, &id_token)); - EXPECT_TRUE(at.empty()); + std::make_unique<std::string>("foo"), &token_response)); + EXPECT_TRUE(token_response.access_token.empty()); } TEST_F(OAuth2AccessTokenFetcherImplTest, ParseGetAccessTokenResponseNoAccessToken) { - std::string at; - int expires_in; - std::string id_token; + OAuth2AccessTokenConsumer::TokenResponse token_response; EXPECT_FALSE(OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( - std::make_unique<std::string>(kTokenResponseNoAccessToken), &at, - &expires_in, &id_token)); - EXPECT_TRUE(at.empty()); + std::make_unique<std::string>(kTokenResponseNoAccessToken), + &token_response)); + EXPECT_TRUE(token_response.access_token.empty()); } TEST_F(OAuth2AccessTokenFetcherImplTest, ParseGetAccessTokenResponseSuccess) { - std::string at; - int expires_in; - std::string id_token; + OAuth2AccessTokenConsumer::TokenResponse token_response; EXPECT_TRUE(OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( - std::make_unique<std::string>(kValidTokenResponse), &at, &expires_in, - &id_token)); - EXPECT_EQ("at1", at); - EXPECT_EQ(3600, expires_in); - EXPECT_EQ("id_token", id_token); + std::make_unique<std::string>(kValidTokenResponse), &token_response)); + EXPECT_EQ("at1", token_response.access_token); + base::TimeDelta expires_in = + token_response.expiration_time - base::Time::Now(); + EXPECT_LT(0, expires_in.InSeconds()); + EXPECT_GT(3600, expires_in.InSeconds()); + EXPECT_EQ("id_token", token_response.id_token); } TEST_F(OAuth2AccessTokenFetcherImplTest,
diff --git a/google_apis/gaia/oauth2_access_token_manager_unittest.cc b/google_apis/gaia/oauth2_access_token_manager_unittest.cc index 0faaceae..e343dae 100644 --- a/google_apis/gaia/oauth2_access_token_manager_unittest.cc +++ b/google_apis/gaia/oauth2_access_token_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "base/memory/ref_counted.h" #include "base/test/task_environment.h" +#include "google_apis/gaia/gaia_access_token_fetcher.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -38,9 +39,10 @@ OAuth2AccessTokenConsumer* consumer) override { EXPECT_NE(account_ids_to_refresh_tokens_.find(account_id), account_ids_to_refresh_tokens_.end()); - return std::make_unique<OAuth2AccessTokenFetcherImpl>( - consumer, url_loader_factory, - account_ids_to_refresh_tokens_[account_id]); + return GaiaAccessTokenFetcher:: + CreateExchangeRefreshTokenForAccessTokenInstance( + consumer, url_loader_factory, + account_ids_to_refresh_tokens_[account_id]); } bool HasRefreshToken(const CoreAccountId& account_id) const override {
diff --git a/ios/chrome/browser/web/error_page_egtest.mm b/ios/chrome/browser/web/error_page_egtest.mm index 765b054..3e857656 100644 --- a/ios/chrome/browser/web/error_page_egtest.mm +++ b/ios/chrome/browser/web/error_page_egtest.mm
@@ -6,6 +6,7 @@ #include <string> #include "base/bind.h" +#import "base/test/ios/wait_util.h" #import "ios/chrome/browser/ui/tab_switcher/tab_grid/features.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" @@ -65,6 +66,40 @@ GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); } +// Tests that the error page is correctly displayed after navigating back to it +// multiple times. See http://crbug.com/944037 . +- (void)testBackForwardErrorPage { + // Using ERR_CONNECTION_CLOSED doesn't work. + std::string errorText = net::ErrorToShortString(net::ERR_INVALID_URL); + self.serverRespondsWithContent = YES; + + [ChromeEarlGrey loadURL:GURL("chrome://invalid")]; + [ChromeEarlGrey waitForWebStateContainingText:errorText]; + // Add some delay otherwise the back/forward navigations are occurring too + // fast. + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.2)); + + // Navigate to a page which responds. + [ChromeEarlGrey loadURL:self.testServer->GetURL("/echo-query?bar")]; + [ChromeEarlGrey waitForWebStateContainingText:"bar"]; + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.2)); + + [ChromeEarlGrey goBack]; + [ChromeEarlGrey waitForWebStateContainingText:errorText]; + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.2)); + + [ChromeEarlGrey goForward]; + [ChromeEarlGrey waitForWebStateContainingText:"bar"]; + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.2)); + + [ChromeEarlGrey goBack]; + [ChromeEarlGrey waitForWebStateContainingText:errorText]; + base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSecondsD(0.2)); + + [ChromeEarlGrey goForward]; + [ChromeEarlGrey waitForWebStateContainingText:"bar"]; +} + // Loads the URL which fails to load, then sucessfully reloads the page. - (void)testReloadErrorPage { // No response leads to ERR_CONNECTION_CLOSED error.
diff --git a/ios/web/js_messaging/BUILD.gn b/ios/web/js_messaging/BUILD.gn index 011d8244..7466714 100644 --- a/ios/web/js_messaging/BUILD.gn +++ b/ios/web/js_messaging/BUILD.gn
@@ -69,6 +69,7 @@ deps = [ "//base", "//base/test:test_support", + "//ios/testing:embedded_test_server_support", "//ios/web/common", "//ios/web/js_messaging", "//ios/web/public",
diff --git a/ios/web/js_messaging/web_frame_web_state_observer_inttest.mm b/ios/web/js_messaging/web_frame_web_state_observer_inttest.mm index a4d3a368..4c1efdccb 100644 --- a/ios/web/js_messaging/web_frame_web_state_observer_inttest.mm +++ b/ios/web/js_messaging/web_frame_web_state_observer_inttest.mm
@@ -5,10 +5,15 @@ #import "ios/web/public/test/web_test_with_web_state.h" #include "base/ios/ios_util.h" +#include "ios/testing/embedded_test_server_handlers.h" #import "ios/web/public/js_messaging/web_frame.h" #import "ios/web/public/js_messaging/web_frames_manager.h" +#import "ios/web/public/test/navigation_test_util.h" +#import "ios/web/public/test/web_view_content_test_util.h" #import "ios/web/public/web_state.h" #include "ios/web/public/web_state_observer.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/request_handler_util.h" #include "testing/gmock/include/gmock/gmock.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -58,7 +63,18 @@ namespace web { -using WebFrameWebStateObserverInttest = WebTestWithWebState; +class WebFrameWebStateObserverInttest : public WebTestWithWebState { + protected: + void SetUp() override { + WebTestWithWebState::SetUp(); + test_server_.RegisterRequestHandler(base::BindRepeating( + &net::test_server::HandlePrefixedRequest, "/echo-query", + base::BindRepeating(&testing::HandlePageWithContents))); + ASSERT_TRUE(test_server_.Start()); + } + + net::EmbeddedTestServer test_server_; +}; // Web frame events should be registered on HTTP navigation. TEST_F(WebFrameWebStateObserverInttest, SingleWebFrameHTTP) { @@ -66,12 +82,18 @@ web_state()->AddObserver(&observer); EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); - LoadHtml(@"<p></p>", GURL("http://testurl1")); + + test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); + EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); - LoadHtml(@"<p></p>", GURL("http://testurl2")); + + test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?secondPage")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "secondPage")); + web_state()->RemoveObserver(&observer); } @@ -79,14 +101,28 @@ TEST_F(WebFrameWebStateObserverInttest, SingleWebFrameHTTPS) { testing::StrictMock<WebStateObserverMock> observer; web_state()->AddObserver(&observer); + EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); - LoadHtml(@"<p></p>", GURL("https://testurl1")); + + // Load a first page to avoid having an item inserted during the |LoadHtml|. + test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); + EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) .WillOnce(VerifyMainWebFrame(web_state())); + + LoadHtml(@"<p></p>", GURL("https://testurl1")); + + EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) + .WillOnce(VerifyMainWebFrame(web_state())); + EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) + .WillOnce(VerifyMainWebFrame(web_state())); + LoadHtml(@"<p></p>", GURL("https://testurl2")); + web_state()->RemoveObserver(&observer); } @@ -95,6 +131,13 @@ testing::StrictMock<WebStateObserverMock> observer; web_state()->AddObserver(&observer); + EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), testing::_)) + .WillOnce(VerifyMainWebFrame(web_state())); + + // Load a first page to avoid having an item inserted during the |LoadHtml|. + test::LoadUrl(web_state(), test_server_.GetURL("/echo-query?test")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "test")); + // The order in which the main and child frames become available is not // guaranteed due to the async nature of messaging. The following expectations // use separate matchers to identify main and child frames so that they can @@ -105,6 +148,9 @@ EXPECT_CALL(observer, WebFrameDidBecomeAvailable(web_state(), Not(Truly(IsMainFrame)))) .WillOnce(VerifyChildWebFrame(web_state())); + EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), testing::_)) + .WillOnce(VerifyMainWebFrame(web_state())); + LoadHtml(@"<p><iframe/></p>", GURL("https://testurl1")); EXPECT_CALL(observer, @@ -119,6 +165,7 @@ EXPECT_CALL(observer, WebFrameWillBecomeUnavailable(web_state(), Not(Truly(IsMainFrame)))) .WillOnce(VerifyChildWebFrame(web_state())); + LoadHtml(@"<p><iframe/></p>", GURL("https://testurl2")); web_state()->RemoveObserver(&observer);
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm index 7e790e31..7ff4abf 100644 --- a/ios/web/navigation/crw_wk_navigation_handler.mm +++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -983,9 +983,7 @@ !context->GetUrl().SchemeIs(url::kAboutScheme) && !IsRestoreSessionUrl(context->GetUrl())) { [self.delegate webViewHandlerUpdateSSLStatusForCurrentNavigationItem:self]; - if ((base::FeatureList::IsEnabled(web::features::kUseJSForErrorPage) || - !context->IsLoadingErrorPage()) && - !IsRestoreSessionUrl(webViewURL)) { + if (!context->IsLoadingErrorPage() && !IsRestoreSessionUrl(webViewURL)) { [self setLastCommittedNavigationItemTitle:webView.title]; } } @@ -1999,13 +1997,16 @@ ErrorPageHelper* errorPage = [[ErrorPageHelper alloc] initWithError:error]; WKBackForwardListItem* backForwardItem = webView.backForwardList.currentItem; - // There are 3 possible scenarios here: + // There are 4 possible scenarios here: // 1. Current nav item is an error page for failed URL; // 2. Current nav item has a failed URL. This may happen when // back/forward/refresh on a loaded page; // 3. Current nav item is an irrelevant page. // 4. Current nav item is a session restoration. - // For 1, 2 and 4, load an empty string to remove existing JS code. + // For 1, 2 and 4, load an empty string to remove existing JS code. The URL is + // also updated to the URL of the page that failed to allow back/forward + // navigations even on navigations originating from pushstate. See + // crbug.com/1153261. // For 3, load error page file to create a new nav item. // The actual error HTML will be loaded in didFinishNavigation callback. WKNavigation* errorNavigation = nil; @@ -2017,7 +2018,8 @@ errorNavigation = [webView loadFileURL:errorPage.errorPageFileURL allowingReadAccessToURL:errorPage.errorPageFileURL]; } else { - errorNavigation = [webView loadHTMLString:@"" baseURL:backForwardItem.URL]; + errorNavigation = [webView loadHTMLString:@"" + baseURL:errorPage.failedNavigationURL]; } [self.navigationStates setState:web::WKNavigationState::REQUESTED forNavigation:errorNavigation];
diff --git a/ios/web/navigation/error_retry_state_machine_unittest.mm b/ios/web/navigation/error_retry_state_machine_unittest.mm index ce203c6f..d1de6fda 100644 --- a/ios/web/navigation/error_retry_state_machine_unittest.mm +++ b/ios/web/navigation/error_retry_state_machine_unittest.mm
@@ -4,6 +4,8 @@ #include "ios/web/navigation/error_retry_state_machine.h" +#include "base/test/scoped_feature_list.h" +#import "ios/web/common/features.h" #include "ios/web/navigation/wk_navigation_util.h" #import "ios/web/public/web_client.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,7 +21,15 @@ static const char kTestUrl[] = "http://test.com"; -typedef PlatformTest ErrorRetryStateMachineTest; +class ErrorRetryStateMachineTest : public PlatformTest { + public: + ErrorRetryStateMachineTest() { + scoped_feature_list_.InitAndDisableFeature(features::kUseJSForErrorPage); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; // Tests load failure during provisional navigation. TEST_F(ErrorRetryStateMachineTest, OfflineThenReload) {
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm index 441e4ee..3db816bd 100644 --- a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm +++ b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
@@ -317,6 +317,9 @@ // Tests that AddPendingItem does not create a new NavigationItem if the new // pending item is a reload of app-specific URL. TEST_F(WKBasedNavigationManagerTest, ReusePendingItemForReloadAppSpecificURL) { + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) + return; + // Simulate a previous app-specific navigation. NSString* url = @"about:blank?for=chrome%3A%2F%2Fnewtab"; [mock_wk_list_ setCurrentURL:url];
diff --git a/ios/web/navigation/wk_navigation_util_unittest.mm b/ios/web/navigation/wk_navigation_util_unittest.mm index 16c714d6..06275ad 100644 --- a/ios/web/navigation/wk_navigation_util_unittest.mm +++ b/ios/web/navigation/wk_navigation_util_unittest.mm
@@ -438,8 +438,14 @@ EXPECT_FALSE(URLNeedsUserAgentType( non_user_agent_urls.ReplaceComponents(scheme_replacements))); - // Not a placeholder or normal URL. - EXPECT_TRUE(URLNeedsUserAgentType(GURL("about:blank?for="))); + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // about:blank pages. + EXPECT_FALSE(URLNeedsUserAgentType(GURL("about:blank"))); + } else { + // Not a placeholder. + EXPECT_TRUE(URLNeedsUserAgentType(GURL("about:blank?for="))); + } + // Normal URL. EXPECT_TRUE(URLNeedsUserAgentType(GURL("http://www.0.com"))); // file:// URL.
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm index 823d1a7..7ee0c26 100644 --- a/ios/web/web_state/error_page_inttest.mm +++ b/ios/web/web_state/error_page_inttest.mm
@@ -167,6 +167,11 @@ #define MAYBE_BackForwardErrorPage FLAKY_BackForwardErrorPage #endif TEST_F(ErrorPageTest, MAYBE_BackForwardErrorPage) { + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // TODO(crbug.com/1151938): Check if the test can be re-enabled with higher + // version of WebKit. + return; + } test::LoadUrl(web_state(), server_.GetURL("/close-socket")); ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/close-socket"))); @@ -220,7 +225,14 @@ server_responds_with_content_ = false; test::LoadUrl(web_state(), server_.GetURL("/echo-query?foo")); ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/echo-query?foo"))); - ASSERT_FALSE(security_state_info()); + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + ASSERT_TRUE(security_state_info()); + ASSERT_TRUE(security_state_info()->visible_ssl_status); + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, + security_state_info()->visible_ssl_status->security_style); + } else { + ASSERT_FALSE(security_state_info()); + } // Reload the page, which should load without errors. server_responds_with_content_ = true; @@ -244,8 +256,13 @@ ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/echo-query?foo"))); ASSERT_TRUE(security_state_info()); ASSERT_TRUE(security_state_info()->visible_ssl_status); - EXPECT_EQ(SECURITY_STYLE_UNKNOWN, - security_state_info()->visible_ssl_status->security_style); + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, + security_state_info()->visible_ssl_status->security_style); + } else { + EXPECT_EQ(SECURITY_STYLE_UNKNOWN, + security_state_info()->visible_ssl_status->security_style); + } } // Sucessfully loads the page, goes back, stops the server, goes forward and @@ -278,8 +295,13 @@ ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/echo-query?foo"))); ASSERT_TRUE(security_state_info()); ASSERT_TRUE(security_state_info()->visible_ssl_status); - EXPECT_EQ(SECURITY_STYLE_UNKNOWN, - security_state_info()->visible_ssl_status->security_style); + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, + security_state_info()->visible_ssl_status->security_style); + } else { + EXPECT_EQ(SECURITY_STYLE_UNKNOWN, + security_state_info()->visible_ssl_status->security_style); + } #endif // TARGET_IPHONE_SIMULATOR } @@ -304,8 +326,13 @@ ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/close-socket"))); ASSERT_TRUE(security_state_info()); ASSERT_TRUE(security_state_info()->visible_ssl_status); - EXPECT_EQ(SECURITY_STYLE_UNKNOWN, - security_state_info()->visible_ssl_status->security_style); + if (base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, + security_state_info()->visible_ssl_status->security_style); + } else { + EXPECT_EQ(SECURITY_STYLE_UNKNOWN, + security_state_info()->visible_ssl_status->security_style); + } } // Sucessfully loads the page, then loads the URL which fails to load, then
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm index 25ace0c..ae8287d3 100644 --- a/ios/web/web_state/web_state_observer_inttest.mm +++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -998,9 +998,11 @@ EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE)); - // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. - EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(observer_, DidStopLoading(web_state())); + if (!base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + } test::LoadUrl(web_state(), url); @@ -1013,7 +1015,7 @@ testing::CreateConnectionLostError(), /*is_post=*/false, /*is_otr=*/false, /*cert_status=*/0))); - DCHECK_EQ(item->GetTitle(), base::UTF8ToUTF16(kFailedTitle)); + EXPECT_EQ(item->GetTitle(), base::UTF8ToUTF16(kFailedTitle)); } // Tests navigation to a URL with /..; suffix. On iOS 12 and earlier this @@ -1131,9 +1133,11 @@ EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE)); - // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. - EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(observer_, DidStopLoading(web_state())); + if (!base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + } test::LoadUrl(web_state(), url); NSError* error = testing::CreateErrorWithUnderlyingErrorChain( @@ -1177,9 +1181,11 @@ EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE)); - // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. - EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(observer_, DidStopLoading(web_state())); + if (!base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + } test::LoadUrl(web_state(), url); NSError* error = testing::CreateErrorWithUnderlyingErrorChain( @@ -1993,9 +1999,11 @@ EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE)); - // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. - EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(observer_, DidStopLoading(web_state())); + if (!base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // Load error page HTML by [WKWebView loadHTMLString:baseURL:]. + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + } test::LoadUrl(web_state(), url); @@ -2036,9 +2044,11 @@ EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::FAILURE)); - // Finally, the error page itself is loaded. - EXPECT_CALL(observer_, DidStartLoading(web_state())); - EXPECT_CALL(observer_, DidStopLoading(web_state())); + if (!base::FeatureList::IsEnabled(features::kUseJSForErrorPage)) { + // Finally, the error page itself is loaded. + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + } test::LoadUrl(web_state(), url); EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ @@ -2085,7 +2095,6 @@ WebStatePolicyDecider::PolicyDecision::CancelAndDisplayError(error))); EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); - EXPECT_CALL(observer_, TitleWasSet(web_state())); EXPECT_CALL(observer_, DidStopLoading(web_state())); EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)); EXPECT_CALL(observer_,
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc index d993ac3..7e9bf64 100644 --- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -17,6 +17,7 @@ #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "base/sequence_checker.h" +#include "base/stl_util.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/threading/thread_task_runner_handle.h" @@ -221,25 +222,17 @@ } // Prepare exif. - const uint8_t* exif_buffer; + const uint8_t* exif_buffer = nullptr; size_t exif_buffer_size = 0; if (exif_mapping) { exif_buffer = static_cast<const uint8_t*>(exif_mapping->memory()); exif_buffer_size = exif_mapping->size(); - } else { - exif_buffer = nullptr; } - // When the exif buffer contains a thumbnail, the VAAPI encoder would - // generate a corrupted JPEG. We can work around the problem by supplying an - // all-zero buffer with the same size and fill in the real exif buffer after - // encoding. - // TODO(shenghao): Remove this mechanism after b/79840013 is fixed. - std::vector<uint8_t> exif_buffer_dummy(exif_buffer_size, 0); - size_t exif_offset = 0; - if (!jpeg_encoder_->Encode(input_size, exif_buffer_dummy.data(), - exif_buffer_size, quality, blit_surface->id(), - cached_output_buffer_->id(), &exif_offset)) { + if (!jpeg_encoder_->Encode(input_size, /*exif_buffer=*/nullptr, + /*exif_buffer_size=*/0u, quality, + blit_surface->id(), cached_output_buffer_->id(), + /*exif_offset=*/nullptr)) { VLOGF(1) << "Encode JPEG failed"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE); return; @@ -268,12 +261,14 @@ return; } - bool isMapped = output_gmb_buffer->Map(); - if (!isMapped) { + const bool is_mapped = output_gmb_buffer->Map(); + if (!is_mapped) { VLOGF(1) << "Map the output gmb buffer failed"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE); return; } + base::ScopedClosureRunner output_gmb_buffer_unmapper(base::BindOnce( + &gfx::GpuMemoryBuffer::Unmap, base::Unretained(output_gmb_buffer.get()))); // Get the encoded output. DownloadFromVABuffer() is a blocking call. It // would wait until encoding is finished. @@ -282,22 +277,82 @@ // Since the format of |output_gmb_buffer| is gfx::BufferFormat::R_8, we can // use its area as the maximum bytes we need to download to avoid buffer // overflow. - if (!vaapi_wrapper_->DownloadFromVABuffer( - cached_output_buffer_->id(), blit_surface->id(), - static_cast<uint8_t*>(output_memory), - output_gmb_buffer->GetSize().GetArea(), &encoded_size)) { - VLOGF(1) << "Failed to retrieve output image from VA coded buffer"; + // Since we didn't supply EXIF data to the JPEG encoder, it creates a default + // APP0 segment in the header. We will download the result to an offset and + // replace the APP0 segment by APP1 including EXIF data: + // SOI + APP0 (2 + 2 + 14 bytes) + other data + // -> SOI + APP1 (2 + 2 + |exif_buffer_size| bytes) + other data + // Note that |exif_buffer_size| >= 14 since EXIF + TIFF headers are 14 bytes, + // and <= (2^16-1)-2 since APP1 data size is stored in 2 bytes. + // TODO(b/171369066, b/171340559): Remove this workaround when Intel iHD + // driver has fixed the EXIF handling. + constexpr size_t kApp0DataSize = 14; + constexpr size_t kMaxExifSize = ((1u << 16) - 1) - 2; + if (exif_buffer_size > 0 && + (exif_buffer_size < kApp0DataSize || exif_buffer_size > kMaxExifSize)) { + VLOGF(1) << "Unexpected EXIF data size (" << exif_buffer_size << ")"; notify_error_cb_.Run(task_id, PLATFORM_FAILURE); - - output_gmb_buffer->Unmap(); return; } + const size_t output_offset = + exif_buffer_size > 0 ? exif_buffer_size - kApp0DataSize : 0; + const size_t output_size = + base::checked_cast<size_t>(output_gmb_buffer->GetSize().GetArea()); + if (output_offset >= output_size) { + VLOGF(1) << "Output buffer size (" << output_size << ") is too small"; + notify_error_cb_.Run(task_id, PLATFORM_FAILURE); + return; + } + uint8_t* frame_content = output_memory + output_offset; + const size_t max_frame_size = output_size - output_offset; + if (!vaapi_wrapper_->DownloadFromVABuffer(cached_output_buffer_->id(), + blit_surface->id(), frame_content, + max_frame_size, &encoded_size)) { + VLOGF(1) << "Failed to retrieve output image from VA coded buffer"; + notify_error_cb_.Run(task_id, PLATFORM_FAILURE); + return; + } + DCHECK_LE(encoded_size, max_frame_size); - // Copy the real exif buffer into preserved space. - memcpy(static_cast<uint8_t*>(output_memory) + exif_offset, exif_buffer, - exif_buffer_size); + if (exif_buffer_size > 0) { + // Check the output header is 2+2+14 bytes APP0 as expected. + constexpr uint8_t kJpegSoiAndApp0Header[] = { + 0xFF, JPEG_SOI, 0xFF, JPEG_APP0, 0x00, 0x10, + }; + if (encoded_size < base::size(kJpegSoiAndApp0Header)) { + VLOGF(1) << "Unexpected JPEG data size received from encoder"; + notify_error_cb_.Run(task_id, PLATFORM_FAILURE); + return; + } + for (size_t i = 0; i < base::size(kJpegSoiAndApp0Header); ++i) { + if (frame_content[i] != kJpegSoiAndApp0Header[i]) { + VLOGF(1) << "Unexpected JPEG header received from encoder"; + notify_error_cb_.Run(task_id, PLATFORM_FAILURE); + return; + } + } + // Copy the EXIF data into preserved space. + const uint8_t jpeg_soi_and_app1_header[] = { + 0xFF, + JPEG_SOI, + 0xFF, + JPEG_APP1, + static_cast<uint8_t>((exif_buffer_size + 2) / 256), + static_cast<uint8_t>((exif_buffer_size + 2) % 256), + }; + DCHECK_GE(output_size, base::size(jpeg_soi_and_app1_header)); + if (exif_buffer_size > output_size - base::size(jpeg_soi_and_app1_header)) { + VLOGF(1) << "Insufficient buffer size reserved for JPEG APP1 data"; + notify_error_cb_.Run(task_id, PLATFORM_FAILURE); + return; + } + memcpy(output_memory, jpeg_soi_and_app1_header, + base::size(jpeg_soi_and_app1_header)); + memcpy(output_memory + base::size(jpeg_soi_and_app1_header), exif_buffer, + exif_buffer_size); + encoded_size += output_offset; + } - output_gmb_buffer->Unmap(); video_frame_ready_cb_.Run(task_id, encoded_size); }
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc index 4d4df80fe..a357d2e 100644 --- a/net/dns/dns_config_service_posix.cc +++ b/net/dns/dns_config_service_posix.cc
@@ -115,7 +115,8 @@ bool Watch(const CallbackType& callback) { callback_ = callback; - return watcher_.Watch(base::FilePath(kFilePathConfig), false, + return watcher_.Watch(base::FilePath(kFilePathConfig), + base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&DnsConfigWatcher::OnCallback, base::Unretained(this))); }
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc index 37fd844..1d6dcaf 100644 --- a/net/dns/dns_config_service_win.cc +++ b/net/dns/dns_config_service_win.cc
@@ -620,7 +620,8 @@ dnscache_watcher_.Watch(kDnscachePath, callback); policy_watcher_.Watch(kPolicyPath, callback); - if (!hosts_watcher_.Watch(GetHostsPath(), false, + if (!hosts_watcher_.Watch(GetHostsPath(), + base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&Watcher::OnHostsChanged, base::Unretained(this)))) { UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus",
diff --git a/remoting/host/config_file_watcher.cc b/remoting/host/config_file_watcher.cc index 74d500f..3b60ec79 100644 --- a/remoting/host/config_file_watcher.cc +++ b/remoting/host/config_file_watcher.cc
@@ -142,7 +142,7 @@ // Start watching the configuration file. config_watcher_.reset(new base::FilePathWatcher()); if (!config_watcher_->Watch( - config_path_, false, + config_path_, base::FilePathWatcher::Type::kNonRecursive, base::BindRepeating(&ConfigFileWatcherImpl::OnConfigUpdated, this))) { PLOG(ERROR) << "Couldn't watch file '" << config_path_.value() << "'"; main_task_runner_->PostTask(
diff --git a/remoting/host/linux/audio_pipe_reader.cc b/remoting/host/linux/audio_pipe_reader.cc index fdd4a39..4f44c2f 100644 --- a/remoting/host/linux/audio_pipe_reader.cc +++ b/remoting/host/linux/audio_pipe_reader.cc
@@ -69,7 +69,7 @@ DCHECK(task_runner_->BelongsToCurrentThread()); if (!file_watcher_.Watch( - pipe_path_.DirName(), true, + pipe_path_.DirName(), base::FilePathWatcher::Type::kRecursive, base::BindRepeating(&AudioPipeReader::OnDirectoryChanged, base::Unretained(this)))) { LOG(ERROR) << "Failed to watch pulseaudio directory "
diff --git a/remoting/host/linux/certificate_watcher.cc b/remoting/host/linux/certificate_watcher.cc index b5541937..ee031ee 100644 --- a/remoting/host/linux/certificate_watcher.cc +++ b/remoting/host/linux/certificate_watcher.cc
@@ -113,7 +113,7 @@ // base::Unretained() is safe since this class owns the FileWatcher. file_watcher_->Watch( - cert_watch_path_, true, + cert_watch_path_, base::FilePathWatcher::Type::kRecursive, base::BindRepeating(&CertDbContentWatcher::OnCertDirectoryChanged, base::Unretained(this)));
diff --git a/services/device/time_zone_monitor/time_zone_monitor_linux.cc b/services/device/time_zone_monitor/time_zone_monitor_linux.cc index 9f69bd6..d5f2abc2 100644 --- a/services/device/time_zone_monitor/time_zone_monitor_linux.cc +++ b/services/device/time_zone_monitor/time_zone_monitor_linux.cc
@@ -129,8 +129,9 @@ }; for (size_t index = 0; index < base::size(kFilesToWatch); ++index) { file_path_watchers_.push_back(std::make_unique<base::FilePathWatcher>()); - file_path_watchers_.back()->Watch(base::FilePath(kFilesToWatch[index]), - false, callback); + file_path_watchers_.back()->Watch( + base::FilePath(kFilesToWatch[index]), + base::FilePathWatcher::Type::kNonRecursive, callback); } }
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index b7136a2e..6ae5567e 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -8496,7 +8496,8 @@ }, { "args": [ - "--test-launcher-print-test-stdio=always" + "--test-launcher-print-test-stdio=always", + "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter" ], "merge": { "args": [], @@ -10440,7 +10441,8 @@ }, { "args": [ - "--test-launcher-print-test-stdio=always" + "--test-launcher-print-test-stdio=always", + "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter" ], "merge": { "args": [],
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index b1d2f10..30b308f 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2722,6 +2722,9 @@ }, }, 'Linux Chromium OS ASan LSan Tests (1)': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter', + ], # These are slow on the ASAN trybot for some reason. # crbug.com/794372 'swarming': { @@ -2729,6 +2732,9 @@ }, }, 'Linux ChromiumOS MSan Tests': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.unit_tests.filter', + ], # These are very slow on the Chrome OS MSAN trybot for some reason. # crbug.com/865455 'swarming': {
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index cbf5b3db..e95e3758e 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -221,7 +221,7 @@ // Controls whether the implementation of the performance.measureMemory // web API uses PerformanceManager or not. const base::Feature kWebMeasureMemoryViaPerformanceManager{ - "WebMeasureMemoryViaPerformanceManager", base::FEATURE_DISABLED_BY_DEFAULT}; + "WebMeasureMemoryViaPerformanceManager", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables negotiation of experimental multiplex codec in SDP. const base::Feature kWebRtcMultiplexCodec{"WebRTC-MultiplexCodec",
diff --git a/third_party/blink/public/mojom/input/synchronous_compositor.mojom b/third_party/blink/public/mojom/input/synchronous_compositor.mojom index 04f130f..a1a266fb5 100644 --- a/third_party/blink/public/mojom/input/synchronous_compositor.mojom +++ b/third_party/blink/public/mojom/input/synchronous_compositor.mojom
@@ -10,6 +10,7 @@ import "services/viz/public/mojom/compositing/compositor_frame.mojom"; import "services/viz/public/mojom/compositing/compositor_frame_metadata.mojom"; import "services/viz/public/mojom/compositing/frame_timing_details.mojom"; +import "services/viz/public/mojom/compositing/local_surface_id.mojom"; import "services/viz/public/mojom/compositing/returned_resource.mojom"; import "services/viz/public/mojom/hit_test/hit_test_region_list.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom"; @@ -56,6 +57,7 @@ (SyncCompositorCommonRendererParams result, uint32 layer_tree_frame_sink_id, uint32 metadata_version, + viz.mojom.LocalSurfaceId? local_surface_id, viz.mojom.CompositorFrame? frame, viz.mojom.HitTestRegionList? hit_test_region_list); @@ -143,6 +145,7 @@ // Response from DrawHwAsync. ReturnFrame(uint32 layer_tree_frame_sink_id, uint32 metadata_version, + viz.mojom.LocalSurfaceId? local_surface_id, viz.mojom.CompositorFrame? frame, viz.mojom.HitTestRegionList? hit_test_region_list);
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom index 577cc64..0935f62 100644 --- a/third_party/blink/public/mojom/payments/payment_request.mojom +++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -38,7 +38,8 @@ USER_CANCEL, NOT_SUPPORTED, NOT_SUPPORTED_FOR_INVALID_ORIGIN_OR_SSL, - ALREADY_SHOWING + ALREADY_SHOWING, + INVALID_DATA_FROM_RENDERER, }; enum CanMakePaymentQueryResult {
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 1e74ccf..9cbbff8 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -263,6 +263,7 @@ deps = [ "//build:chromeos_buildflags", "//components/paint_preview/common", + "//components/performance_manager/public/mojom:mojom_blink", "//components/shared_highlighting/core/common", "//gpu/config", "//mojo/public/cpp/bindings:bindings",
diff --git a/third_party/blink/renderer/core/editing/inline_box_position.cc b/third_party/blink/renderer/core/editing/inline_box_position.cc index d20b9b55..14cab4d 100644 --- a/third_party/blink/renderer/core/editing/inline_box_position.cc +++ b/third_party/blink/renderer/core/editing/inline_box_position.cc
@@ -366,11 +366,6 @@ return ComputeInlineBoxPositionTemplate<EditingInFlatTreeStrategy>(position); } -InlineBoxPosition ComputeInlineBoxPosition(const VisiblePosition& position) { - DCHECK(position.IsValid()) << position; - return ComputeInlineBoxPosition(position.ToPositionWithAffinity()); -} - PositionWithAffinity ComputeInlineAdjustedPosition( const PositionWithAffinity& position) { return ComputeInlineAdjustedPositionAlgorithm(position, 0); @@ -381,13 +376,6 @@ return ComputeInlineAdjustedPositionAlgorithm(position, 0); } -PositionWithAffinity ComputeInlineAdjustedPosition( - const VisiblePosition& position) { - DCHECK(position.IsValid()) << position; - return ComputeInlineAdjustedPositionAlgorithm( - position.ToPositionWithAffinity(), 0); -} - InlineBoxPosition ComputeInlineBoxPositionForInlineAdjustedPosition( const PositionWithAffinity& position) { return ComputeInlineBoxPositionForInlineAdjustedPositionAlgorithm(position);
diff --git a/third_party/blink/renderer/core/editing/inline_box_position.h b/third_party/blink/renderer/core/editing/inline_box_position.h index 3d58ea1..5dab73e 100644 --- a/third_party/blink/renderer/core/editing/inline_box_position.h +++ b/third_party/blink/renderer/core/editing/inline_box_position.h
@@ -69,12 +69,10 @@ ComputeInlineBoxPosition(const PositionWithAffinity&); CORE_EXPORT InlineBoxPosition ComputeInlineBoxPosition(const PositionInFlatTreeWithAffinity&); -CORE_EXPORT InlineBoxPosition ComputeInlineBoxPosition(const VisiblePosition&); PositionWithAffinity ComputeInlineAdjustedPosition(const PositionWithAffinity&); PositionInFlatTreeWithAffinity ComputeInlineAdjustedPosition( const PositionInFlatTreeWithAffinity&); -PositionWithAffinity ComputeInlineAdjustedPosition(const VisiblePosition&); InlineBoxPosition ComputeInlineBoxPositionForInlineAdjustedPosition( const PositionWithAffinity&);
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.cc b/third_party/blink/renderer/core/editing/selection_modifier.cc index 61766be..91c8b81 100644 --- a/third_party/blink/renderer/core/editing/selection_modifier.cc +++ b/third_party/blink/renderer/core/editing/selection_modifier.cc
@@ -74,11 +74,11 @@ VisiblePosition SelectionModifier::PreviousParagraphPosition( const VisiblePosition& passed_position, LayoutUnit x_point) { - DCHECK(passed_position.IsValid()) << passed_position; VisiblePosition position = passed_position; do { - const VisiblePosition& new_position = - PreviousLinePosition(position, x_point); + DCHECK(position.IsValid()) << position; + const VisiblePosition& new_position = CreateVisiblePosition( + PreviousLinePosition(position.ToPositionWithAffinity(), x_point)); if (new_position.IsNull() || new_position.DeepEquivalent() == position.DeepEquivalent()) break; @@ -91,10 +91,11 @@ VisiblePosition SelectionModifier::NextParagraphPosition( const VisiblePosition& passed_position, LayoutUnit x_point) { - DCHECK(passed_position.IsValid()) << passed_position; VisiblePosition position = passed_position; do { - const VisiblePosition& new_position = NextLinePosition(position, x_point); + DCHECK(position.IsValid()) << position; + const VisiblePosition& new_position = CreateVisiblePosition( + NextLinePosition(position.ToPositionWithAffinity(), x_point)); if (new_position.IsNull() || new_position.DeepEquivalent() == position.DeepEquivalent()) break; @@ -151,7 +152,8 @@ namespace { -base::Optional<TextDirection> DirectionAt(const VisiblePosition& position) { +base::Optional<TextDirection> DirectionAt( + const PositionWithAffinity& position) { if (position.IsNull()) return base::nullopt; const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position); @@ -173,7 +175,8 @@ } // TODO(xiaochengh): Deduplicate code with |DirectionAt()|. -base::Optional<TextDirection> LineDirectionAt(const VisiblePosition& position) { +base::Optional<TextDirection> LineDirectionAt( + const PositionWithAffinity& position) { if (position.IsNull()) return base::nullopt; const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position); @@ -198,9 +201,9 @@ TextDirection DirectionOf(const VisibleSelection& visible_selection) { base::Optional<TextDirection> maybe_start_direction = - DirectionAt(visible_selection.VisibleStart()); + DirectionAt(visible_selection.VisibleStart().ToPositionWithAffinity()); base::Optional<TextDirection> maybe_end_direction = - DirectionAt(visible_selection.VisibleEnd()); + DirectionAt(visible_selection.VisibleEnd().ToPositionWithAffinity()); if (maybe_start_direction.has_value() && maybe_end_direction.has_value() && maybe_start_direction.value() == maybe_end_direction.value()) return maybe_start_direction.value(); @@ -215,7 +218,7 @@ } TextDirection SelectionModifier::LineDirectionOfExtent() const { - return LineDirectionAt(selection_.VisibleExtent()) + return LineDirectionAt(selection_.VisibleExtent().ToPositionWithAffinity()) .value_or(DirectionOfEnclosingBlockOf(selection_.Extent())); } @@ -382,11 +385,17 @@ return CreateVisiblePosition(NextWordPositionForPlatform( ComputeVisibleExtent(selection_).DeepEquivalent())); case TextGranularity::kSentence: - return NextSentencePosition(ComputeVisibleExtent(selection_)); - case TextGranularity::kLine: - return NextLinePosition( - ComputeVisibleExtent(selection_), - LineDirectionPointForBlockDirectionNavigation(selection_.Extent())); + return CreateVisiblePosition( + NextSentencePosition( + ComputeVisibleExtent(selection_).DeepEquivalent()), + TextAffinity::kUpstreamIfPossible); + case TextGranularity::kLine: { + const VisiblePosition& pos = ComputeVisibleExtent(selection_); + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition(NextLinePosition( + pos.ToPositionWithAffinity(), + LineDirectionPointForBlockDirectionNavigation(selection_.Extent()))); + } case TextGranularity::kParagraph: return NextParagraphPosition( ComputeVisibleExtent(selection_), @@ -399,8 +408,11 @@ return EndOfParagraph(EndForPlatform()); case TextGranularity::kDocumentBoundary: { const VisiblePosition& pos = EndForPlatform(); - if (IsEditablePosition(pos.DeepEquivalent())) - return EndOfEditableContent(pos); + if (IsEditablePosition(pos.DeepEquivalent())) { + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition( + EndOfEditableContent(pos.DeepEquivalent())); + } return EndOfDocument(pos); } } @@ -462,7 +474,10 @@ return CreateVisiblePosition(NextWordPositionForPlatform( ComputeVisibleExtent(selection_).DeepEquivalent())); case TextGranularity::kSentence: - return NextSentencePosition(ComputeVisibleExtent(selection_)); + return CreateVisiblePosition( + NextSentencePosition( + ComputeVisibleExtent(selection_).DeepEquivalent()), + TextAffinity::kUpstreamIfPossible); case TextGranularity::kLine: { // down-arrowing from a range selection that ends at the start of a line // needs to leave the selection at that line start (no need to call @@ -470,9 +485,10 @@ const VisiblePosition& pos = EndForPlatform(); if (selection_.IsRange() && IsStartOfLine(pos)) return pos; - return NextLinePosition( - pos, - LineDirectionPointForBlockDirectionNavigation(selection_.Start())); + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition(NextLinePosition( + pos.ToPositionWithAffinity(), + LineDirectionPointForBlockDirectionNavigation(selection_.Start()))); } case TextGranularity::kParagraph: return NextParagraphPosition( @@ -486,8 +502,11 @@ return EndOfParagraph(EndForPlatform()); case TextGranularity::kDocumentBoundary: { const VisiblePosition& pos = EndForPlatform(); - if (IsEditablePosition(pos.DeepEquivalent())) - return EndOfEditableContent(pos); + if (IsEditablePosition(pos.DeepEquivalent())) { + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition( + EndOfEditableContent(pos.DeepEquivalent())); + } return EndOfDocument(pos); } } @@ -556,11 +575,15 @@ return CreateVisiblePosition(PreviousWordPosition( ComputeVisibleExtent(selection_).DeepEquivalent())); case TextGranularity::kSentence: - return PreviousSentencePosition(ComputeVisibleExtent(selection_)); - case TextGranularity::kLine: - return PreviousLinePosition( - ComputeVisibleExtent(selection_), - LineDirectionPointForBlockDirectionNavigation(selection_.Extent())); + return CreateVisiblePosition(PreviousSentencePosition( + ComputeVisibleExtent(selection_).DeepEquivalent())); + case TextGranularity::kLine: { + const VisiblePosition& pos = ComputeVisibleExtent(selection_); + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition(PreviousLinePosition( + pos.ToPositionWithAffinity(), + LineDirectionPointForBlockDirectionNavigation(selection_.Extent()))); + } case TextGranularity::kParagraph: return PreviousParagraphPosition( ComputeVisibleExtent(selection_), @@ -573,8 +596,11 @@ return StartOfParagraph(StartForPlatform()); case TextGranularity::kDocumentBoundary: { const VisiblePosition pos = StartForPlatform(); - if (IsEditablePosition(pos.DeepEquivalent())) - return StartOfEditableContent(pos); + if (IsEditablePosition(pos.DeepEquivalent())) { + DCHECK(pos.IsValid()) << pos; + return CreateVisiblePosition( + StartOfEditableContent(pos.DeepEquivalent())); + } return StartOfDocument(pos); } } @@ -639,13 +665,17 @@ ComputeVisibleExtent(selection_).DeepEquivalent())); break; case TextGranularity::kSentence: - pos = PreviousSentencePosition(ComputeVisibleExtent(selection_)); + pos = CreateVisiblePosition(PreviousSentencePosition( + ComputeVisibleExtent(selection_).DeepEquivalent())); break; - case TextGranularity::kLine: - pos = PreviousLinePosition( - StartForPlatform(), - LineDirectionPointForBlockDirectionNavigation(selection_.Start())); + case TextGranularity::kLine: { + const VisiblePosition& start = StartForPlatform(); + DCHECK(start.IsValid()) << start; + pos = CreateVisiblePosition(PreviousLinePosition( + start.ToPositionWithAffinity(), + LineDirectionPointForBlockDirectionNavigation(selection_.Start()))); break; + } case TextGranularity::kParagraph: pos = PreviousParagraphPosition( StartForPlatform(), @@ -662,10 +692,13 @@ break; case TextGranularity::kDocumentBoundary: pos = StartForPlatform(); - if (IsEditablePosition(pos.DeepEquivalent())) - pos = StartOfEditableContent(pos); - else + if (IsEditablePosition(pos.DeepEquivalent())) { + DCHECK(pos.IsValid()) << pos; + pos = + CreateVisiblePosition(StartOfEditableContent(pos.DeepEquivalent())); + } else { pos = StartOfDocument(pos); + } break; } return pos; @@ -813,9 +846,8 @@ } // TODO(yosin): Maybe baseline would be better? -static bool AbsoluteCaretY(const VisiblePosition& c, int& y) { - DCHECK(c.IsValid()) << c; - IntRect rect = AbsoluteCaretBoundsOf(c.ToPositionWithAffinity()); +static bool AbsoluteCaretY(const PositionWithAffinity& c, int& y) { + IntRect rect = AbsoluteCaretBoundsOf(c); if (rect.IsEmpty()) return false; y = rect.Y() + rect.Height() / 2; @@ -860,7 +892,8 @@ } int start_y; - if (!AbsoluteCaretY(pos, start_y)) + DCHECK(pos.IsValid()) << pos; + if (!AbsoluteCaretY(pos.ToPositionWithAffinity(), start_y)) return false; if (direction == SelectionModifyVerticalDirection::kUp) start_y = -start_y; @@ -873,15 +906,19 @@ iteration_count < kMaxIterationForPageGranularityMovement; p = next) { ++iteration_count; - if (direction == SelectionModifyVerticalDirection::kUp) - next = PreviousLinePosition(p, x_pos); - else - next = NextLinePosition(p, x_pos); + if (direction == SelectionModifyVerticalDirection::kUp) { + next = CreateVisiblePosition( + PreviousLinePosition(p.ToPositionWithAffinity(), x_pos)); + } else { + next = CreateVisiblePosition( + NextLinePosition(p.ToPositionWithAffinity(), x_pos)); + } if (next.IsNull() || next.DeepEquivalent() == p.DeepEquivalent()) break; int next_y; - if (!AbsoluteCaretY(next, next_y)) + DCHECK(next.IsValid()) << next; + if (!AbsoluteCaretY(next.ToPositionWithAffinity(), next_y)) break; if (direction == SelectionModifyVerticalDirection::kUp) next_y = -next_y;
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.h b/third_party/blink/renderer/core/editing/selection_modifier.h index 0beea62..db0e55f 100644 --- a/third_party/blink/renderer/core/editing/selection_modifier.h +++ b/third_party/blink/renderer/core/editing/selection_modifier.h
@@ -102,10 +102,11 @@ VisiblePosition ModifyMovingBackward(TextGranularity); Position NextWordPositionForPlatform(const Position&); - static VisiblePosition PreviousLinePosition(const VisiblePosition&, - LayoutUnit line_direction_point); - static VisiblePosition NextLinePosition(const VisiblePosition&, - LayoutUnit line_direction_point); + static PositionWithAffinity PreviousLinePosition( + const PositionWithAffinity&, + LayoutUnit line_direction_point); + static PositionWithAffinity NextLinePosition(const PositionWithAffinity&, + LayoutUnit line_direction_point); static VisiblePosition PreviousParagraphPosition( const VisiblePosition&, LayoutUnit line_direction_point);
diff --git a/third_party/blink/renderer/core/editing/selection_modifier_line.cc b/third_party/blink/renderer/core/editing/selection_modifier_line.cc index 7ee6536..1623cdf9 100644 --- a/third_party/blink/renderer/core/editing/selection_modifier_line.cc +++ b/third_party/blink/renderer/core/editing/selection_modifier_line.cc
@@ -51,7 +51,7 @@ public: AbstractLineBox() = default; - static AbstractLineBox CreateFor(const VisiblePosition&); + static AbstractLineBox CreateFor(const PositionWithAffinity&); bool IsNull() const { return type_ == Type::kNull; } @@ -249,9 +249,10 @@ }; // static -AbstractLineBox AbstractLineBox::CreateFor(const VisiblePosition& position) { +AbstractLineBox AbstractLineBox::CreateFor( + const PositionWithAffinity& position) { if (position.IsNull() || - !position.DeepEquivalent().AnchorNode()->GetLayoutObject()) { + !position.GetPosition().AnchorNode()->GetLayoutObject()) { return AbstractLineBox(); } @@ -343,18 +344,19 @@ return nullptr; } -bool InSameLine(const Node& node, const VisiblePosition& visible_position) { +bool InSameLine(const Node& node, const PositionWithAffinity& position) { if (!node.GetLayoutObject()) return true; - return InSameLine(CreateVisiblePosition(FirstPositionInOrBeforeNode(node)), - visible_position); + return InSameLine(CreateVisiblePosition(FirstPositionInOrBeforeNode(node)) + .ToPositionWithAffinity(), + position); } Node* FindNodeInPreviousLine(const Node& start_node, - const VisiblePosition& visible_position) { + const PositionWithAffinity& position) { for (Node* runner = PreviousLeafWithSameEditability(start_node); runner; runner = PreviousLeafWithSameEditability(*runner)) { - if (!InSameLine(*runner, visible_position)) + if (!InSameLine(*runner, position)) return runner; } return nullptr; @@ -363,11 +365,9 @@ // FIXME: consolidate with code in previousLinePosition. Position PreviousRootInlineBoxCandidatePosition( Node* node, - const VisiblePosition& visible_position) { - DCHECK(visible_position.IsValid()) << visible_position; - ContainerNode* highest_root = - HighestEditableRoot(visible_position.DeepEquivalent()); - Node* const previous_node = FindNodeInPreviousLine(*node, visible_position); + const PositionWithAffinity& position) { + ContainerNode* highest_root = HighestEditableRoot(position.GetPosition()); + Node* const previous_node = FindNodeInPreviousLine(*node, position); for (Node* runner = previous_node; runner && !runner->IsShadowRoot(); runner = PreviousLeafWithSameEditability(*runner)) { if (HighestEditableRootOfNode(*runner) != highest_root) @@ -385,16 +385,14 @@ Position NextRootInlineBoxCandidatePosition( Node* node, - const VisiblePosition& visible_position) { - DCHECK(visible_position.IsValid()) << visible_position; - ContainerNode* highest_root = - HighestEditableRoot(visible_position.DeepEquivalent()); + const PositionWithAffinity& position) { + ContainerNode* highest_root = HighestEditableRoot(position.GetPosition()); // TODO(xiaochengh): We probably also need to pass in the starting editability // to |PreviousLeafWithSameEditability|. - const bool is_editable = HasEditableStyle( - *visible_position.DeepEquivalent().ComputeContainerNode()); + const bool is_editable = + HasEditableStyle(*position.GetPosition().ComputeContainerNode()); Node* next_node = NextLeafWithGivenEditability(node, is_editable); - while (next_node && InSameLine(*next_node, visible_position)) { + while (next_node && InSameLine(*next_node, position)) { next_node = NextLeafWithGivenEditability(next_node, is_editable); } @@ -414,24 +412,22 @@ } // namespace // static -VisiblePosition SelectionModifier::PreviousLinePosition( - const VisiblePosition& visible_position, +PositionWithAffinity SelectionModifier::PreviousLinePosition( + const PositionWithAffinity& position, LayoutUnit line_direction_point) { - DCHECK(visible_position.IsValid()) << visible_position; - // TODO(xiaochengh): Make all variables |const|. - Position p = visible_position.DeepEquivalent(); + Position p = position.GetPosition(); Node* node = p.AnchorNode(); if (!node) - return VisiblePosition(); + return PositionWithAffinity(); LayoutObject* layout_object = node->GetLayoutObject(); if (!layout_object) - return VisiblePosition(); + return PositionWithAffinity(); - AbstractLineBox line = AbstractLineBox::CreateFor(visible_position); + AbstractLineBox line = AbstractLineBox::CreateFor(position); if (!line.IsNull()) { line = line.PreviousLine(); if (line.IsNull() || !line.CanBeCaretContainer()) @@ -439,15 +435,14 @@ } if (line.IsNull()) { - Position position = - PreviousRootInlineBoxCandidatePosition(node, visible_position); - if (position.IsNotNull()) { - const VisiblePosition candidate = CreateVisiblePosition(position); - line = AbstractLineBox::CreateFor(candidate); + Position candidate = PreviousRootInlineBoxCandidatePosition(node, position); + if (candidate.IsNotNull()) { + line = AbstractLineBox::CreateFor( + CreateVisiblePosition(candidate).ToPositionWithAffinity()); if (line.IsNull()) { // TODO(editing-dev): Investigate if this is correct for null - // |candidate|. - return candidate; + // |CreateVisiblePosition(candidate)|. + return PositionWithAffinity(candidate); } } } @@ -457,18 +452,17 @@ PhysicalOffset point_in_line = line.AbsoluteLineDirectionPointToLocalPointInBlock( line_direction_point); - if (auto position = + if (auto candidate = line.PositionForPoint(point_in_line, IsEditablePosition(p))) { // If the current position is inside an editable position, then the next // shouldn't end up inside non-editable as that would cross the editing // boundaries which would be an invalid selection. if (IsEditablePosition(p) && - !IsEditablePosition(position.GetPosition())) { - return CreateVisiblePosition( - AdjustBackwardPositionToAvoidCrossingEditingBoundaries( - position, visible_position.DeepEquivalent())); + !IsEditablePosition(candidate.GetPosition())) { + return AdjustBackwardPositionToAvoidCrossingEditingBoundaries(candidate, + p); } - return CreateVisiblePosition(position); + return candidate; } } @@ -479,29 +473,27 @@ ? RootEditableElement(*node) : node->GetDocument().documentElement(); if (!root_element) - return VisiblePosition(); - return VisiblePosition::FirstPositionInNode(*root_element); + return PositionWithAffinity(); + return PositionWithAffinity(Position::FirstPositionInNode(*root_element)); } // static -VisiblePosition SelectionModifier::NextLinePosition( - const VisiblePosition& visible_position, +PositionWithAffinity SelectionModifier::NextLinePosition( + const PositionWithAffinity& position, LayoutUnit line_direction_point) { - DCHECK(visible_position.IsValid()) << visible_position; - // TODO(xiaochengh): Make all variables |const|. - Position p = visible_position.DeepEquivalent(); + Position p = position.GetPosition(); Node* node = p.AnchorNode(); if (!node) - return VisiblePosition(); + return PositionWithAffinity(); LayoutObject* layout_object = node->GetLayoutObject(); if (!layout_object) - return VisiblePosition(); + return PositionWithAffinity(); - AbstractLineBox line = AbstractLineBox::CreateFor(visible_position); + AbstractLineBox line = AbstractLineBox::CreateFor(position); if (!line.IsNull()) { line = line.NextLine(); if (line.IsNull() || !line.CanBeCaretContainer()) @@ -513,15 +505,15 @@ Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset()); Node* search_start_node = child ? child : &NodeTraversal::LastWithinOrSelf(*node); - Position position = - NextRootInlineBoxCandidatePosition(search_start_node, visible_position); - if (position.IsNotNull()) { - const VisiblePosition candidate = CreateVisiblePosition(position); - line = AbstractLineBox::CreateFor(candidate); + Position candidate = + NextRootInlineBoxCandidatePosition(search_start_node, position); + if (candidate.IsNotNull()) { + line = AbstractLineBox::CreateFor( + CreateVisiblePosition(candidate).ToPositionWithAffinity()); if (line.IsNull()) { // TODO(editing-dev): Investigate if this is correct for null - // |candidate|. - return candidate; + // |CreateVisiblePosition(candidate)|. + return PositionWithAffinity(candidate); } } } @@ -531,18 +523,17 @@ PhysicalOffset point_in_line = line.AbsoluteLineDirectionPointToLocalPointInBlock( line_direction_point); - if (auto position = + if (auto candidate = line.PositionForPoint(point_in_line, IsEditablePosition(p))) { // If the current position is inside an editable position, then the next // shouldn't end up inside non-editable as that would cross the editing // boundaries which would be an invalid selection. if (IsEditablePosition(p) && - !IsEditablePosition(position.GetPosition())) { - return CreateVisiblePosition( - AdjustForwardPositionToAvoidCrossingEditingBoundaries( - position, visible_position.DeepEquivalent())); + !IsEditablePosition(candidate.GetPosition())) { + return AdjustForwardPositionToAvoidCrossingEditingBoundaries(candidate, + p); } - return CreateVisiblePosition(position); + return candidate; } } @@ -553,8 +544,8 @@ ? RootEditableElement(*node) : node->GetDocument().documentElement(); if (!root_element) - return VisiblePosition(); - return VisiblePosition::LastPositionInNode(*root_element); + return PositionWithAffinity(); + return PositionWithAffinity(Position::LastPositionInNode(*root_element)); } } // namespace blink
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc index 9807ced0..1ae38de 100644 --- a/third_party/blink/renderer/core/editing/visible_units.cc +++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -452,25 +452,20 @@ // --------- -VisiblePosition StartOfEditableContent( - const VisiblePosition& visible_position) { - DCHECK(visible_position.IsValid()) << visible_position; - ContainerNode* highest_root = - HighestEditableRoot(visible_position.DeepEquivalent()); +Position StartOfEditableContent(const Position& position) { + ContainerNode* highest_root = HighestEditableRoot(position); if (!highest_root) - return VisiblePosition(); + return Position(); - return VisiblePosition::FirstPositionInNode(*highest_root); + return Position::FirstPositionInNode(*highest_root); } -VisiblePosition EndOfEditableContent(const VisiblePosition& visible_position) { - DCHECK(visible_position.IsValid()) << visible_position; - ContainerNode* highest_root = - HighestEditableRoot(visible_position.DeepEquivalent()); +Position EndOfEditableContent(const Position& position) { + ContainerNode* highest_root = HighestEditableRoot(position); if (!highest_root) - return VisiblePosition(); + return Position(); - return VisiblePosition::LastPositionInNode(*highest_root); + return Position::LastPositionInNode(*highest_root); } bool IsEndOfEditableOrNonEditableContent(const VisiblePosition& position) {
diff --git a/third_party/blink/renderer/core/editing/visible_units.h b/third_party/blink/renderer/core/editing/visible_units.h index 16fa1fb5..473ff89 100644 --- a/third_party/blink/renderer/core/editing/visible_units.h +++ b/third_party/blink/renderer/core/editing/visible_units.h
@@ -151,8 +151,8 @@ CORE_EXPORT VisiblePosition EndOfSentence(const VisiblePosition&); CORE_EXPORT VisiblePositionInFlatTree EndOfSentence(const VisiblePositionInFlatTree&); -VisiblePosition PreviousSentencePosition(const VisiblePosition&); -VisiblePosition NextSentencePosition(const VisiblePosition&); +Position PreviousSentencePosition(const Position&); +Position NextSentencePosition(const Position&); EphemeralRange ExpandEndToSentenceBoundary(const EphemeralRange&); EphemeralRange ExpandRangeToSentenceBoundary(const EphemeralRange&); @@ -240,8 +240,8 @@ bool IsEndOfDocument(const VisiblePosition&); // editable content -VisiblePosition StartOfEditableContent(const VisiblePosition&); -VisiblePosition EndOfEditableContent(const VisiblePosition&); +Position StartOfEditableContent(const Position&); +Position EndOfEditableContent(const Position&); CORE_EXPORT bool IsEndOfEditableOrNonEditableContent(const VisiblePosition&); CORE_EXPORT bool IsEndOfEditableOrNonEditableContent( const VisiblePositionInFlatTree&);
diff --git a/third_party/blink/renderer/core/editing/visible_units_sentence.cc b/third_party/blink/renderer/core/editing/visible_units_sentence.cc index 8a328f5..3293563 100644 --- a/third_party/blink/renderer/core/editing/visible_units_sentence.cc +++ b/third_party/blink/renderer/core/editing/visible_units_sentence.cc
@@ -240,30 +240,15 @@ // ---- -PositionInFlatTreeWithAffinity NextSentencePosition( - const PositionInFlatTree& start) { +PositionInFlatTree NextSentencePosition(const PositionInFlatTree& start) { const PositionInFlatTree result = NextSentencePositionInternal(start); return AdjustForwardPositionToAvoidCrossingEditingBoundaries( - PositionInFlatTreeWithAffinity(result), start); + PositionInFlatTreeWithAffinity(result), start) + .GetPosition(); } -PositionWithAffinity NextSentencePosition(const Position& start) { - const PositionInFlatTreeWithAffinity result = - NextSentencePosition(ToPositionInFlatTree(start)); - return ToPositionInDOMTreeWithAffinity(result); -} - -VisiblePosition NextSentencePosition(const VisiblePosition& c) { - return CreateVisiblePosition( - NextSentencePosition(c.DeepEquivalent()).GetPosition(), - TextAffinity::kUpstreamIfPossible); -} - -VisiblePositionInFlatTree NextSentencePosition( - const VisiblePositionInFlatTree& c) { - return CreateVisiblePosition( - NextSentencePosition(c.DeepEquivalent()).GetPosition(), - TextAffinity::kUpstreamIfPossible); +Position NextSentencePosition(const Position& start) { + return ToPositionInDOMTree(NextSentencePosition(ToPositionInFlatTree(start))); } // ---- @@ -283,10 +268,6 @@ PreviousSentencePosition(ToPositionInFlatTree(position))); } -VisiblePosition PreviousSentencePosition(const VisiblePosition& c) { - return CreateVisiblePosition(PreviousSentencePosition(c.DeepEquivalent())); -} - // ---- PositionInFlatTree StartOfSentencePosition(const PositionInFlatTree& position) {
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index 72e3444f..95f0aa2 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -686,6 +686,11 @@ if (window->GetFrame()) deprecation = &window->GetFrame()->GetPage()->GetDeprecation(); } else if (auto* scope = DynamicTo<WorkerOrWorkletGlobalScope>(context)) { + // TODO(crbug.com/1146824): Remove this once PlzDedicatedWorker and + // PlzServiceWorker ship. + if (!scope->IsInitialized()) { + return; + } deprecation = &scope->GetDeprecation(); }
diff --git a/third_party/blink/renderer/core/frame/navigator.h b/third_party/blink/renderer/core/frame/navigator.h index e88c35c1..5eb1673 100644 --- a/third_party/blink/renderer/core/frame/navigator.h +++ b/third_party/blink/renderer/core/frame/navigator.h
@@ -39,7 +39,9 @@ // NavigatorCookies bool cookieEnabled() const; - bool webdriver() const { return true; } + bool webdriver() const { + return RuntimeEnabledFeatures::AutomationControlledEnabled(); + } String productSub() const; String vendor() const;
diff --git a/third_party/blink/renderer/core/frame/navigator_automation_information.idl b/third_party/blink/renderer/core/frame/navigator_automation_information.idl index 3d7ca44..047fa67 100644 --- a/third_party/blink/renderer/core/frame/navigator_automation_information.idl +++ b/third_party/blink/renderer/core/frame/navigator_automation_information.idl
@@ -4,8 +4,6 @@ // https://w3c.github.io/webdriver/#interface -[ - RuntimeEnabled=AutomationControlled -] interface mixin NavigatorAutomationInformation { +interface mixin NavigatorAutomationInformation { readonly attribute boolean webdriver; };
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc index cbdc861..05cff13 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -580,7 +580,8 @@ } is_in_reset_function_ = false; - frame->GetPage()->GetChromeClient().FormElementReset(*this); + if (frame->GetPage()) + frame->GetPage()->GetChromeClient().FormElementReset(*this); } void HTMLFormElement::ParseAttribute(
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc index 5b02043..966621d 100644 --- a/third_party/blink/renderer/core/html/forms/html_input_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -1195,9 +1195,8 @@ if (value_changed) { NotifyFormStateChanged(); - if (value.IsEmpty() && HasBeenPasswordField()) { - GetDocument().GetFrame()->GetPage()->GetChromeClient().PasswordFieldReset( - *this); + if (value.IsEmpty() && HasBeenPasswordField() && GetDocument().GetPage()) { + GetDocument().GetPage()->GetChromeClient().PasswordFieldReset(*this); } } }
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc index 366f86b22..eec78a97 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -776,8 +776,13 @@ } } if (this_box && this_box->IsGridItem() && - this_box->HasOverrideContainingBlockContentLogicalHeight()) + this_box->HasOverrideContainingBlockContentLogicalHeight()) { + if (RuntimeEnabledFeatures::TableCellNewPercentsEnabled()) { + return this_box->OverrideContainingBlockContentLogicalHeight() == + kIndefiniteSize; + } return false; + } if (this_box && this_box->IsCustomItem() && (this_box->HasOverrideContainingBlockContentLogicalHeight() || this_box->HasOverridePercentageResolutionBlockSize()))
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 9e6f3957..e62ce56 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -89,6 +89,7 @@ #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h" #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h" +#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h" #include "third_party/blink/renderer/core/layout/svg/svg_resources.h" @@ -2104,6 +2105,31 @@ return StyleRef(); } +const ComputedStyle* LayoutObject::SlowStyleForContinuationOutline() const { + NOT_DESTROYED(); + // Fail fast using bitfields is done in |StyleForContinuationOutline|. + DCHECK(IsAnonymous() && !IsInline()); + const auto* block_flow = DynamicTo<LayoutBlockFlow>(this); + if (!block_flow) + return nullptr; + + // Check ancestors of the continuation in case nested inline boxes; e.g. + // <span style="outline: auto"> + // <span> + // <div>block</div> + // </span> + // </span> + for (const LayoutObject* continuation = block_flow->Continuation(); + UNLIKELY(continuation && continuation->IsLayoutInline()); + continuation = continuation->Parent()) { + const ComputedStyle& style = continuation->StyleRef(); + if (style.OutlineStyleIsAuto() && + NGOutlineUtils::HasPaintedOutline(style, continuation->GetNode())) + return &style; + } + return nullptr; +} + // Called when an object that was floating or positioned becomes a normal flow // object again. We have to make sure the layout tree updates as needed to // accommodate the new normal flow object.
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 3aea8e86..0e30a3e 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1325,6 +1325,15 @@ NOT_DESTROYED(); return nullptr; } + // Returns the |ComputedStyle| to use for painting outlines. When |this| is + // a block in a continuation-chain, it may need to paint outlines if its + // ancestor inline boxes in the DOM tree has outlines. + const ComputedStyle* StyleForContinuationOutline() const { + NOT_DESTROYED(); + if (UNLIKELY(IsAnonymous() && !IsInline())) + return SlowStyleForContinuationOutline(); + return nullptr; + } bool IsFloating() const { NOT_DESTROYED(); @@ -3590,6 +3599,8 @@ LayoutFlowThread* LocateFlowThreadContainingBlock() const; void RemoveFromLayoutFlowThreadRecursive(LayoutFlowThread*); + const ComputedStyle* SlowStyleForContinuationOutline() const; + StyleDifference AdjustStyleDifference(StyleDifference) const; #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.cc b/third_party/blink/renderer/core/layout/layout_replaced.cc index 00c8003b..0dee4d4 100644 --- a/third_party/blink/renderer/core/layout/layout_replaced.cc +++ b/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -135,6 +135,10 @@ if (StyleRef().LogicalHeight().IsAuto()) return StretchBlockSizeIfAuto(); + if (RuntimeEnabledFeatures::TableCellNewPercentsEnabled() && + StyleRef().LogicalHeight().IsFixed()) + return true; + if (StyleRef().LogicalHeight().IsSpecified()) { if (HasAutoHeightOrContainingBlockWithAutoHeight()) return false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index c9ab641..d34fb9c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -1090,8 +1090,7 @@ // Issue full invalidation, in case the number of column rules have // changed. needs_full_invalidation = true; - } else if (block->IsAnonymous() && !block->IsInline() && - block->IsLayoutBlockFlow() && block->Continuation()) { + } else if (block->StyleForContinuationOutline()) { // When this is a block-in-inline created by |SplineInlines|, we may need // to paint outlines for this. See |NGBoxFragmentPainter|. needs_full_invalidation = true;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h index 396a64c..58cd4b5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -226,6 +226,15 @@ const HitTestLocation& hit_test_location, const PhysicalOffset& accumulated_offset) const; + // Returns the |ComputedStyle| to use for painting outlines. When |this| is + // a block in a continuation-chain, it may need to paint outlines if its + // ancestor inline boxes in the DOM tree has outlines. + const ComputedStyle* StyleForContinuationOutline() const { + if (const auto* layout_object = GetLayoutObject()) + return layout_object->StyleForContinuationOutline(); + return nullptr; + } + // Fragment offset is this fragment's offset from parent. // Needed to compensate for LayoutInline Legacy code offsets. void AddSelfOutlineRects(const PhysicalOffset& additional_offset,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 60c1894..75ed2f3 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -374,35 +374,6 @@ return 0; } -// Returns the |ComputedStyle| to use for painting outlines. When |fragment| is -// a block in a continuation-chain, it may need to paint outlines if its -// ancestor inline boxes in the DOM tree has outlines. -const ComputedStyle* StyleForContinuationOutline( - const NGPhysicalBoxFragment& fragment) { - // Fail fast if |fragment| is not a anonymous block. - const LayoutObject* layout_object = fragment.GetLayoutObject(); - if (!layout_object || !layout_object->IsAnonymous() || - layout_object->IsInline()) - return nullptr; - - // Check ancestors of the continuation in case nested inline boxes; e.g. - // <span style="outline: auto"> - // <span> - // <div>block</div> - // </span> - // </span> - for (const LayoutObject* continuation = - To<LayoutBoxModelObject>(layout_object)->Continuation(); - continuation && continuation->IsLayoutInline(); - continuation = continuation->Parent()) { - const ComputedStyle& style = continuation->StyleRef(); - if (style.OutlineStyleIsAuto() && - NGOutlineUtils::HasPaintedOutline(style, continuation->GetNode())) - return &style; - } - return nullptr; -} - } // anonymous namespace PhysicalRect NGBoxFragmentPainter::SelfInkOverflow() const { @@ -677,7 +648,7 @@ } } else if (ShouldPaintDescendantOutlines(paint_phase)) { if (const ComputedStyle* outline_style = - StyleForContinuationOutline(fragment)) { + fragment.StyleForContinuationOutline()) { NGFragmentPainter(fragment, GetDisplayItemClient()) .PaintOutline(paint_info, paint_offset, *outline_style); }
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc index a5444d2..8e22200 100644 --- a/third_party/blink/renderer/core/paint/paint_invalidator.cc +++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -69,8 +69,7 @@ object.StyleRef().HasOutline()) || // If this is a block-in-inline, it may need to paint outline. // See |StyleForContinuationOutline|. - (layout_block_flow && layout_block_flow->IsAnonymous() && - !layout_block_flow->IsInline() && layout_block_flow->Continuation()))) + (layout_block_flow && layout_block_flow->StyleForContinuationOutline()))) context.painting_layer->SetNeedsPaintPhaseDescendantOutlines(); }
diff --git a/third_party/blink/renderer/core/timing/build.gni b/third_party/blink/renderer/core/timing/build.gni index f0b692b..016200a 100644 --- a/third_party/blink/renderer/core/timing/build.gni +++ b/third_party/blink/renderer/core/timing/build.gni
@@ -17,8 +17,6 @@ "layout_shift_attribution.h", "measure_memory/measure_memory_controller.cc", "measure_memory/measure_memory_controller.h", - "measure_memory/measure_memory_delegate.cc", - "measure_memory/measure_memory_delegate.h", "memory_info.cc", "memory_info.h", "performance.cc",
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc index 9c362ef8..4e45ebf 100644 --- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc +++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -4,11 +4,12 @@ #include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h" -#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h" - +#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h" #include "third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h" #include "third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -20,10 +21,17 @@ #include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "v8/include/v8.h" +using performance_manager::mojom::blink::WebMemoryAttribution; +using performance_manager::mojom::blink::WebMemoryAttributionPtr; +using performance_manager::mojom::blink::WebMemoryBreakdownEntryPtr; +using performance_manager::mojom::blink::WebMemoryMeasurement; +using performance_manager::mojom::blink::WebMemoryMeasurementPtr; + namespace blink { MeasureMemoryController::MeasureMemoryController( @@ -61,26 +69,28 @@ exception_state.RethrowV8Exception(try_catch.Exception()); return ScriptPromise(); } - v8::MeasureMemoryExecution execution = + auto measurement_mode = RuntimeEnabledFeatures::ForceEagerMeasureMemoryEnabled( ExecutionContext::From(script_state)) - ? v8::MeasureMemoryExecution::kEager - : v8::MeasureMemoryExecution::kDefault; + ? WebMemoryMeasurement::Mode::kEager + : WebMemoryMeasurement::Mode::kDefault; auto* impl = MakeGarbageCollected<MeasureMemoryController>( base::PassKey<MeasureMemoryController>(), isolate, context, promise_resolver); + Document* document = LocalDOMWindow::From(script_state)->document(); + document->GetResourceCoordinator()->OnWebMemoryMeasurementRequested( + measurement_mode, WTF::Bind(&MeasureMemoryController::MeasurementComplete, + WrapPersistent(impl))); - isolate->MeasureMemory( - std::make_unique<MeasureMemoryDelegate>( - isolate, context, - WTF::Bind(&MeasureMemoryController::MainMeasurementComplete, - WrapPersistent(impl))), - execution); return ScriptPromise(script_state, promise_resolver->GetPromise()); } bool MeasureMemoryController::IsMeasureMemoryAvailable(LocalDOMWindow* window) { + if (!base::FeatureList::IsEnabled( + features::kWebMeasureMemoryViaPerformanceManager)) { + return false; + } if (!window || !window->CrossOriginIsolatedCapability()) { return false; } @@ -91,10 +101,66 @@ if (!local_frame || local_frame->IsCrossOriginToMainFrame()) { return false; } + + // We need DocumentResourceCoordinator to query PerformanceManager. + if (!window->document() || !window->document()->GetResourceCoordinator()) { + return false; + } + return true; } -void MeasureMemoryController::MainMeasurementComplete(Result breakdown) { +namespace { + +// These functions convert WebMemory* mojo structs to IDL and JS values. +WTF::String ConvertScope(WebMemoryAttribution::Scope scope) { + switch (scope) { + case WebMemoryAttribution::Scope::kWindow: + return "Window"; + } +} + +MemoryAttribution* ConvertAttribution( + const WebMemoryAttributionPtr& attribution) { + auto* result = MemoryAttribution::Create(); + result->setUrl(attribution->url); + result->setScope(ConvertScope(attribution->scope)); + result->setContainer(nullptr); + return result; +} + +MemoryBreakdownEntry* ConvertBreakdown( + const WebMemoryBreakdownEntryPtr& breakdown_entry) { + auto* result = MemoryBreakdownEntry::Create(); + result->setBytes(breakdown_entry->bytes); + HeapVector<Member<MemoryAttribution>> attribution; + for (const auto& entry : breakdown_entry->attribution) { + attribution.push_back(ConvertAttribution(entry)); + } + result->setAttribution(attribution); + result->setUserAgentSpecificTypes(Vector<String>()); + return result; +} + +MemoryMeasurement* ConvertResult(const WebMemoryMeasurementPtr& measurement) { + HeapVector<Member<MemoryBreakdownEntry>> breakdown; + for (const auto& entry : measurement->breakdown) { + breakdown.push_back(ConvertBreakdown(entry)); + } + size_t bytes = 0; + for (auto entry : breakdown) { + bytes += entry->bytes(); + } + auto* result = MemoryMeasurement::Create(); + result->setBreakdown(breakdown); + result->setBytes(bytes); + return result; +} + +} // anonymous namespace + +void MeasureMemoryController::MeasurementComplete( + WebMemoryMeasurementPtr measurement) { if (context_.IsEmpty()) { // The context was garbage collected in the meantime. return; @@ -102,13 +168,7 @@ v8::HandleScope handle_scope(isolate_); v8::Local<v8::Context> context = context_.NewLocal(isolate_); v8::Context::Scope context_scope(context); - auto* result = MemoryMeasurement::Create(); - size_t total_size = 0; - for (auto entry : breakdown) { - total_size += entry->bytes(); - } - result->setBytes(total_size); - result->setBreakdown(breakdown); + auto* result = ConvertResult(measurement); v8::Local<v8::Promise::Resolver> promise_resolver = promise_resolver_.NewLocal(isolate_); promise_resolver->Resolve(context, ToV8(result, promise_resolver, isolate_))
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h index 9e1a7f68..6baae0c 100644 --- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h +++ b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_CONTROLLER_H_ #include "base/types/pass_key.h" +#include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h" @@ -17,7 +18,6 @@ namespace blink { class LocalDOMWindow; -class MemoryBreakdownEntry; class ScriptState; class ExceptionState; @@ -30,21 +30,6 @@ class MeasureMemoryController final : public GarbageCollected<MeasureMemoryController> { public: - using Result = HeapVector<Member<MemoryBreakdownEntry>>; - using ResultCallback = base::OnceCallback<void(Result)>; - - // PerformanceManager in blink/renderer/controller uses this interface - // to provide an implementation of memory measurement for dedicated workers. - // - // It will be removed in the future when performance.measureMemory switches - // to a mojo-based implementation that queries PerformanceManager in the - // browser process. - class V8MemoryReporter { - public: - virtual void GetMemoryUsage(MeasureMemoryController::ResultCallback, - v8::MeasureMemoryExecution) = 0; - }; - // Private constructor guarded by PassKey. Use the StartMeasurement() wrapper // to construct the object and start the measurement. MeasureMemoryController(base::PassKey<MeasureMemoryController>, @@ -58,13 +43,11 @@ void Trace(Visitor* visitor) const; - // The entry point for injecting dependency on PerformanceManager. - CORE_EXPORT static void SetDedicatedWorkerMemoryReporter(V8MemoryReporter*); - private: static bool IsMeasureMemoryAvailable(LocalDOMWindow* window); // Invoked when the memory of the main V8 isolate is measured. - void MainMeasurementComplete(Result); + void MeasurementComplete( + performance_manager::mojom::blink::WebMemoryMeasurementPtr); v8::Isolate* isolate_; ScopedPersistent<v8::Context> context_;
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc deleted file mode 100644 index bde7eb2..0000000 --- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.cc +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h" - -#include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/public/platform/web_security_origin.h" -#include "third_party/blink/public/web/web_frame.h" -#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_memory_measurement.h" -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/frame/frame.h" -#include "third_party/blink/renderer/core/frame/frame_owner.h" -#include "third_party/blink/renderer/core/frame/local_dom_window.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" -#include "third_party/blink/renderer/core/html/html_frame_owner_element.h" -#include "third_party/blink/renderer/platform/bindings/script_state.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin.h" - -namespace blink { - -MeasureMemoryDelegate::MeasureMemoryDelegate(v8::Isolate* isolate, - v8::Local<v8::Context> context, - ResultCallback callback) - : isolate_(isolate), - context_(isolate, context), - callback_(std::move(callback)) { - context_.SetPhantom(); -} - -// Returns true if the given context should be included in the current memory -// measurement. Currently it is very conservative and allows only the same -// origin contexts that belong to the same JavaScript origin. -// With COOP/COEP we will be able to relax this restriction for the contexts -// that opt-in into memory measurement. -bool MeasureMemoryDelegate::ShouldMeasure(v8::Local<v8::Context> context) { - if (context_.IsEmpty()) { - // The original context was garbage collected in the meantime. - return false; - } - v8::Local<v8::Context> original_context = context_.NewLocal(isolate_); - ExecutionContext* original_execution_context = - ExecutionContext::From(original_context); - ExecutionContext* execution_context = ExecutionContext::From(context); - if (!original_execution_context || !execution_context) { - // One of the contexts is detached or is created by DevTools. - return false; - } - if (original_execution_context->GetAgent() != execution_context->GetAgent()) { - // Context do not belong to the same JavaScript agent. - return false; - } - if (ScriptState::From(context)->World().IsIsolatedWorld()) { - // Context belongs to an extension. Skip it. - return false; - } - const SecurityOrigin* original_security_origin = - original_execution_context->GetSecurityContext().GetSecurityOrigin(); - const SecurityOrigin* security_origin = - execution_context->GetSecurityContext().GetSecurityOrigin(); - if (!original_security_origin->IsSameOriginWith(security_origin)) { - // TODO(ulan): Allow only same-origin contexts until the implementation - // is switched to PerformanceManager. - return false; - } - return true; -} - -namespace { -// Helper functions for constructing a memory measurement result. - -LocalFrame* GetLocalFrame(v8::Local<v8::Context> context) { - LocalDOMWindow* window = ToLocalDOMWindow(context); - if (!window) { - // The context was detached. Ignore it. - return nullptr; - } - return window->GetFrame(); -} - -String GetUrl(const LocalFrame* requesting_frame, const LocalFrame* frame) { - // Only same-origin frames are reported until we switch to PerformanceManager. - DCHECK(requesting_frame->GetSecurityContext()->GetSecurityOrigin()->CanAccess( - frame->GetSecurityContext()->GetSecurityOrigin())); - return frame->GetDocument()->Url().GetString(); -} - -MemoryAttribution* CreateMemoryAttribution(const String& url) { - auto* result = MemoryAttribution::Create(); - result->setUrl(url); - result->setScope("Window"); - result->setContainer(nullptr); - return result; -} - -MemoryBreakdownEntry* CreateMemoryBreakdownEntry(size_t bytes, - const Vector<String>& types, - const String& url) { - auto* result = MemoryBreakdownEntry::Create(); - result->setBytes(bytes); - result->setUserAgentSpecificTypes(types); - HeapVector<Member<MemoryAttribution>> attribution; - if (url.length()) { - attribution.push_back(CreateMemoryAttribution(url)); - } - result->setAttribution(attribution); - return result; -} - -} // anonymous namespace - -// Constructs a memory measurement result based on the given list of (context, -// size) pairs and resolves the promise. -void MeasureMemoryDelegate::MeasurementComplete( - const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& context_sizes, - size_t unattributed_size) { - if (context_.IsEmpty()) { - // The context was garbage collected in the meantime. - return; - } - v8::Local<v8::Context> context = context_.NewLocal(isolate_); - LocalFrame* requesting_frame = GetLocalFrame(context); - if (!requesting_frame) { - // The context was detached in the meantime. - return; - } - v8::Context::Scope context_scope(context); - size_t total_size = 0; - for (const auto& context_size : context_sizes) { - total_size += context_size.second; - } - HeapVector<Member<MemoryBreakdownEntry>> breakdown; - size_t detached_size = 0; - const String kJS("JS"); - const Vector<String> js_types = {kJS}; - for (const auto& it : context_sizes) { - size_t bytes = it.second; - LocalFrame* frame = GetLocalFrame(it.first); - if (!frame) { - detached_size += bytes; - continue; - } - String url = GetUrl(requesting_frame, frame); - breakdown.push_back(CreateMemoryBreakdownEntry(bytes, js_types, url)); - } - if (detached_size) { - const String kDetached("Detached"); - breakdown.push_back(CreateMemoryBreakdownEntry( - detached_size, Vector<String>{kJS, kDetached}, "")); - } - if (unattributed_size) { - breakdown.push_back( - CreateMemoryBreakdownEntry(unattributed_size, Vector<String>{kJS}, "")); - } - std::move(callback_).Run(breakdown); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h b/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h deleted file mode 100644 index 5bb1f48..0000000 --- a/third_party/blink/renderer/core/timing/measure_memory/measure_memory_delegate.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_ - -#include "third_party/blink/renderer/platform/bindings/scoped_persistent.h" -#include "third_party/blink/renderer/platform/heap/heap_allocator.h" -#include "third_party/blink/renderer/platform/heap/member.h" -#include "v8/include/v8.h" - -namespace blink { - -class MemoryBreakdownEntry; - -// Specifies V8 contexts to be measured and invokes the given callback once V8 -// completes the memory measurement. -class MeasureMemoryDelegate : public v8::MeasureMemoryDelegate { - public: - using ResultCallback = - base::OnceCallback<void(HeapVector<Member<MemoryBreakdownEntry>>)>; - - MeasureMemoryDelegate(v8::Isolate* isolate, - v8::Local<v8::Context> context, - ResultCallback callback); - - // v8::MeasureMemoryDelegate overrides. - bool ShouldMeasure(v8::Local<v8::Context> context) override; - void MeasurementComplete( - const std::vector<std::pair<v8::Local<v8::Context>, size_t>>& - context_sizes, - size_t unattributed_size) override; - private: - v8::Isolate* isolate_; - ScopedPersistent<v8::Context> context_; - ResultCallback callback_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_MEASURE_MEMORY_MEASURE_MEMORY_DELEGATE_H_
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h index e1237af..8d23edf 100644 --- a/third_party/blink/renderer/core/workers/worker_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -85,6 +85,7 @@ void Dispose() override; WorkerThread* GetThread() const final { return thread_; } const base::UnguessableToken& GetDevToolsToken() const override; + bool IsInitialized() const final { return !url_.IsNull(); } void ExceptionUnhandled(int exception_id);
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h index 29e33dc5..9f79c128 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -156,6 +156,10 @@ virtual int GetOutstandingThrottledLimit() const; + // TODO(crbug.com/1146824): Remove this once PlzDedicatedWorker and + // PlzServiceWorker ship. + virtual bool IsInitialized() const = 0; + Deprecation& GetDeprecation() { return deprecation_; } protected:
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.h b/third_party/blink/renderer/core/workers/worklet_global_scope.h index b57faf0..dd8e5528 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -71,6 +71,7 @@ void Dispose() override; WorkerThread* GetThread() const final; const base::UnguessableToken& GetDevToolsToken() const override; + bool IsInitialized() const final { return true; } virtual LocalFrame* GetFrame() const;
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/third_party/blink/renderer/modules/imagecapture/image_capture.cc index 3d312881f..c019993c 100644 --- a/third_party/blink/renderer/modules/imagecapture/image_capture.cc +++ b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -43,6 +43,9 @@ const char kNoServiceError[] = "ImageCapture service unavailable."; +const char kInvalidStateTrackError[] = + "The associated Track is in an invalid state"; + bool TrackIsInactive(const MediaStreamTrack& track) { // Spec instructs to return an exception if the Track's readyState() is not // "live". Also reject if the track is disabled or muted. @@ -183,8 +186,7 @@ if (TrackIsInactive(*stream_track_)) { resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, - "The associated Track is in an invalid state.")); + DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError)); return promise; } @@ -216,8 +218,7 @@ if (TrackIsInactive(*stream_track_)) { resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, - "The associated Track is in an invalid state.")); + DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError)); return promise; } @@ -253,8 +254,7 @@ if (TrackIsInactive(*stream_track_)) { resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, - "The associated Track is in an invalid state.")); + DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError)); return promise; } @@ -342,8 +342,7 @@ if (TrackIsInactive(*stream_track_)) { resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError, - "The associated Track is in an invalid state.")); + DOMExceptionCode::kInvalidStateError, kInvalidStateTrackError)); return promise; } @@ -978,8 +977,7 @@ if (TrackIsInactive(*stream_track_)) { resolver->Reject(MakeGarbageCollected<DOMException>( - DOMExceptionCode::kOperationError, - "The associated Track is in an invalid state.")); + DOMExceptionCode::kOperationError, kInvalidStateTrackError)); service_requests_.erase(resolver); return; }
diff --git a/third_party/blink/renderer/modules/installedapp/BUILD.gn b/third_party/blink/renderer/modules/installedapp/BUILD.gn index 749de147..9eb2ce9 100644 --- a/third_party/blink/renderer/modules/installedapp/BUILD.gn +++ b/third_party/blink/renderer/modules/installedapp/BUILD.gn
@@ -11,5 +11,8 @@ "navigator_installed_app.cc", "navigator_installed_app.h", ] - deps = [ "//third_party/blink/renderer/modules/manifest" ] + deps = [ + "//services/metrics/public/cpp:ukm_builders", + "//third_party/blink/renderer/modules/manifest", + ] }
diff --git a/third_party/blink/renderer/modules/installedapp/DEPS b/third_party/blink/renderer/modules/installedapp/DEPS new file mode 100644 index 0000000..dc115d0 --- /dev/null +++ b/third_party/blink/renderer/modules/installedapp/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+services/metrics/public/cpp", +] \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc b/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc index b9ec220..7a57164 100644 --- a/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc +++ b/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "services/metrics/public/cpp/ukm_builders.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/common/manifest/manifest.h" #include "third_party/blink/public/mojom/installedapp/related_application.mojom-blink.h" @@ -105,6 +106,12 @@ app->setVersion(res->version); applications.push_back(app); } + + LocalDOMWindow* window = GetSupplementable(); + ukm::builders::InstalledRelatedApps(window->UkmSourceID()) + .SetCalled(true) + .Record(window->UkmRecorder()); + callbacks->OnSuccess(applications); }
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc index 3bc7d493..5fe5153 100644 --- a/third_party/blink/renderer/modules/payments/payment_request.cc +++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -1503,6 +1503,10 @@ switch (error) { case PaymentErrorReason::USER_CANCEL: + // Intentional fall through. + case PaymentErrorReason::INVALID_DATA_FROM_RENDERER: + // Intentional fall through. + case PaymentErrorReason::ALREADY_SHOWING: exception_code = DOMExceptionCode::kAbortError; break; @@ -1515,10 +1519,6 @@ not_supported_for_invalid_origin_or_ssl_error_ = error_message; break; - case PaymentErrorReason::ALREADY_SHOWING: - exception_code = DOMExceptionCode::kAbortError; - break; - case PaymentErrorReason::UNKNOWN: break; }
diff --git a/third_party/blink/renderer/platform/instrumentation/BUILD.gn b/third_party/blink/renderer/platform/instrumentation/BUILD.gn index 870af66..122520b 100644 --- a/third_party/blink/renderer/platform/instrumentation/BUILD.gn +++ b/third_party/blink/renderer/platform/instrumentation/BUILD.gn
@@ -37,11 +37,11 @@ "use_counter.h", ] - deps = [ + deps = [ "//services/service_manager/public/cpp" ] + public_deps = [ "//components/performance_manager/public/mojom:mojom_blink", - "//services/service_manager/public/cpp", + "//third_party/blink/renderer/platform/heap:heap", ] - public_deps = [ "//third_party/blink/renderer/platform/heap:heap" ] allow_circular_includes_from = public_deps }
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc index b0a57d7..92acf76 100644 --- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc +++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
@@ -71,4 +71,10 @@ service_->OnFirstContentfulPaint(time_since_navigation_start); } +void DocumentResourceCoordinator::OnWebMemoryMeasurementRequested( + WebMemoryMeasurementMode mode, + OnWebMemoryMeasurementRequestedCallback callback) { + service_->OnWebMemoryMeasurementRequested(mode, std::move(callback)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h index 38573e0..f7d4cfc 100644 --- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h +++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
@@ -21,6 +21,11 @@ USING_FAST_MALLOC(DocumentResourceCoordinator); public: + using WebMemoryMeasurementMode = + ::performance_manager::mojom::blink::WebMemoryMeasurement::Mode; + using OnWebMemoryMeasurementRequestedCallback = ::performance_manager::mojom:: + blink::DocumentCoordinationUnit::OnWebMemoryMeasurementRequestedCallback; + // Returns nullptr if instrumentation is not enabled. static std::unique_ptr<DocumentResourceCoordinator> MaybeCreate( const BrowserInterfaceBrokerProxy&); @@ -35,6 +40,9 @@ void OnNonPersistentNotificationCreated(); void SetHadFormInteraction(); void OnFirstContentfulPaint(base::TimeDelta time_since_navigation_start); + void OnWebMemoryMeasurementRequested( + WebMemoryMeasurementMode mode, + OnWebMemoryMeasurementRequestedCallback callback); private: explicit DocumentResourceCoordinator(const BrowserInterfaceBrokerProxy&);
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc index 52c9b96..a5e27fd 100644 --- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc +++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.cc
@@ -392,9 +392,14 @@ } // NOTE: submit_frame will be empty if viz_frame_submission_enabled_ enabled, // but it won't be used upstream - sync_client_->SubmitCompositorFrame(layer_tree_frame_sink_id_, - std::move(submit_frame), - client_->BuildHitTestData()); + // Because OnDraw can synchronously override the viewport without going + // through commit and activation, we generate our own LocalSurfaceId by + // checking the submitted frame instead of using the one set here. + sync_client_->SubmitCompositorFrame( + layer_tree_frame_sink_id_, + viz_frame_submission_enabled_ ? local_surface_id_ + : child_local_surface_id_, + std::move(submit_frame), client_->BuildHitTestData()); did_submit_frame_ = true; }
diff --git a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h index 8a543664..774140db 100644 --- a/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h +++ b/third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_layer_tree_frame_sink.h
@@ -56,6 +56,7 @@ virtual void Invalidate(bool needs_draw) = 0; virtual void SubmitCompositorFrame( uint32_t layer_tree_frame_sink_id, + const viz::LocalSurfaceId& local_surface_id, base::Optional<viz::CompositorFrame> frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) = 0; virtual void SetNeedsBeginFrames(bool needs_begin_frames) = 0;
diff --git a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc index f7dc657..77a8cf1 100644 --- a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc +++ b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.cc
@@ -133,7 +133,8 @@ if (hardware_draw_reply_) { // Did not swap. std::move(hardware_draw_reply_) - .Run(PopulateNewCommonParams(), 0u, 0u, base::nullopt, base::nullopt); + .Run(PopulateNewCommonParams(), 0u, 0u, base::nullopt, base::nullopt, + base::nullopt); } } @@ -215,6 +216,7 @@ void SynchronousCompositorProxy::SubmitCompositorFrame( uint32_t layer_tree_frame_sink_id, + const viz::LocalSurfaceId& local_surface_id, base::Optional<viz::CompositorFrame> frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) { // Verify that exactly one of these is true. @@ -225,9 +227,10 @@ if (hardware_draw_reply_) { // For viz the CF was submitted directly via CompositorFrameSink DCHECK(frame || viz_frame_submission_enabled_); + DCHECK(local_surface_id.is_valid()); std::move(hardware_draw_reply_) .Run(std::move(common_renderer_params), layer_tree_frame_sink_id, - NextMetadataVersion(), std::move(frame), + NextMetadataVersion(), local_surface_id, std::move(frame), std::move(hit_test_region_list)); } else if (software_draw_reply_) { DCHECK(frame); @@ -332,10 +335,12 @@ mojom::blink::SyncCompositorCommonRendererParamsPtr, uint32_t layer_tree_frame_sink_id, uint32_t metadata_version, + const base::Optional<viz::LocalSurfaceId>& local_surface_id, base::Optional<viz::CompositorFrame> frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) { control_host_->ReturnFrame(layer_tree_frame_sink_id, metadata_version, - std::move(frame), std::move(hit_test_region_list)); + local_surface_id, std::move(frame), + std::move(hit_test_region_list)); } void SynchronousCompositorProxy::SendBeginFrameResponse(
diff --git a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h index 846bbd1..19cfb5c 100644 --- a/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h +++ b/third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h
@@ -59,6 +59,7 @@ void Invalidate(bool needs_draw) final; void SubmitCompositorFrame( uint32_t layer_tree_frame_sink_id, + const viz::LocalSurfaceId& local_surface_id, base::Optional<viz::CompositorFrame> frame, base::Optional<viz::HitTestRegionList> hit_test_region_list) final; void SetNeedsBeginFrames(bool needs_begin_frames) final; @@ -99,6 +100,7 @@ mojom::blink::SyncCompositorCommonRendererParamsPtr, uint32_t layer_tree_frame_sink_id, uint32_t metadata_version, + const base::Optional<viz::LocalSurfaceId>& local_surface_id, base::Optional<viz::CompositorFrame>, base::Optional<viz::HitTestRegionList> hit_test_region_list);
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index beacc9c..4c3ba07 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -722,6 +722,9 @@ crbug.com/591099 external/wpt/css/css-flexbox/position-absolute-014.html [ Failure ] crbug.com/591099 external/wpt/css/css-flexbox/position-absolute-015.html [ Failure ] +### external/wpt/css/css-grid/ +crbug.com/591099 external/wpt/css/css-grid/grid-items/percentage-size-indefinite-replaced.html [ Failure ] + ### external/wpt/css/css-pseudo/ crbug.com/591099 external/wpt/css/css-pseudo/active-selection-011.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index f806d4c..1c91a7b 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3881,6 +3881,7 @@ crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-003.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-004.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-005.html [ Failure ] +crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-indefinite-replaced.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-replaced-subitems-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-subitems-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/remove-svg-grid-item-001.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 191280b7..26c2868 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -208083,7 +208083,7 @@ [] ], "border-shorthand-serialization-expected.txt": [ - "11e3cbab5c713a3d4cdbede0f65f442df2bded53", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", [] ], "cssstyledeclaration-custom-properties-expected.txt": [ @@ -295409,6 +295409,13 @@ {} ] ], + "positon-absolute-scrollable-overflow-001.html": [ + "67e24a247570cdc56033d509e0fb7cbddda17591", + [ + null, + {} + ] + ], "sticky": { "position-sticky-bottom.html": [ "9cfae6d3ba9bdeafa2ff6fcd820dc2c3fdb13660",
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/percentage-size-indefinite-replaced.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/percentage-size-indefinite-replaced.html new file mode 100644 index 0000000..3610f2e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/percentage-size-indefinite-replaced.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1153028"> +<meta name="assert" content="When determining a auto row, an indefinite percentage block-size should be considered auto, and use the inline-size + aspect-ratio."> +<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html"> +<p>Test passes if there is a filled green square.</p> +<div style="display: grid; width: 50px;"> + <canvas width=200 height=200 style="background: green; height: 100%; width: 200%;"></canvas> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/positon-absolute-scrollable-overflow-001.html b/third_party/blink/web_tests/external/wpt/css/css-position/positon-absolute-scrollable-overflow-001.html new file mode 100644 index 0000000..67e24a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/positon-absolute-scrollable-overflow-001.html
@@ -0,0 +1,73 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CSS Positioned Layout Test: Absolute positioned elements are included in the scrollable overflow area</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-position/#valdef-position-absolute"> +<link rel="help" href="https://drafts.csswg.org/css-overflow/#scrollable"> +<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollheight"> +<meta name=assert content="Absolute positioned elements are included in the scrollable overflow area of its containing block."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<style> +.containing-block { + position: relative; + width: 100px; + height: 100px; + margin: 100px; +} + +.abspos { + position: absolute; + background: rgba(0, 255, 0, 0.5); + width: 10px; + height: 10px; + left: 0; + top: 0; +} +</style> +<body onload="checkLayout('.containing-block');"> + <div id="log"></div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="500"> + <div class="abspos" style="left: -50px; height: 500px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="550"> + <div class="abspos" style="left: -50px; height: 500px; top: 50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="700"> + <div class="abspos" style="left: -50px; height: 500px; top: 200px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="400"> + <div class="abspos" style="left: -50px; height: 500px; top: -100px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100"> + <div class="abspos" style="left: -50px; height: 500px; top: -1000px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100"> + <div class="abspos" style="left: 50px; height: 500px; top: -1000px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="210" data-expected-scroll-height="700"> + <div class="abspos" style="left: 200px; height: 500px; top: 200px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="500" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; top: -50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="550" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; left: 50px; top: -50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="700" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; left: 200px; top: -50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="400" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; left: -100px; top: -50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; left: -1000px; top: -50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100"> + <div class="abspos" style="width: 500px; left: -1000px; top: 50px;"></div> + </div> + <div class="containing-block" data-expected-scroll-width="700" data-expected-scroll-height="210"> + <div class="abspos" style="width: 500px; left: 200px; top: 200px;"></div> + </div> +</body>
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index 684a9c0..8e7fa59 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index 3fd986e..e8f2830 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index ea3dd26..4352df4 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index 2c184971..70d2bb64 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -77,6 +77,7 @@ PASS oldChildWindow.navigator.virtualKeyboard.boundingRect.y is newChildWindow.navigator.virtualKeyboard.boundingRect.y PASS oldChildWindow.navigator.virtualKeyboard.ongeometrychange is newChildWindow.navigator.virtualKeyboard.ongeometrychange PASS oldChildWindow.navigator.virtualKeyboard.overlaysContent is newChildWindow.navigator.virtualKeyboard.overlaysContent +PASS oldChildWindow.navigator.webdriver is newChildWindow.navigator.webdriver PASS oldChildWindow.navigator.xr.ondevicechange is newChildWindow.navigator.xr.ondevicechange PASS oldChildWindow.onabort is newChildWindow.onabort PASS oldChildWindow.onafterprint is newChildWindow.onafterprint
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index 9484589..43e29e3 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -43,6 +43,7 @@ PASS childWindow.navigator.virtualKeyboard.boundingRect.y is 0 PASS childWindow.navigator.virtualKeyboard.ongeometrychange is null PASS childWindow.navigator.virtualKeyboard.overlaysContent is false +PASS childWindow.navigator.webdriver is false PASS childWindow.onabort is null PASS childWindow.onafterprint is null PASS childWindow.onanimationend is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index 4210d73..25cc520 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -43,6 +43,7 @@ PASS childWindow.navigator.virtualKeyboard.boundingRect.y is 0 PASS childWindow.navigator.virtualKeyboard.ongeometrychange is null PASS childWindow.navigator.virtualKeyboard.overlaysContent is false +PASS childWindow.navigator.webdriver is false PASS childWindow.onabort is null PASS childWindow.onafterprint is null PASS childWindow.onanimationend is null
diff --git a/third_party/blink/web_tests/fast/mediastream/constructors-expected.txt b/third_party/blink/web_tests/fast/mediastream/constructors-expected.txt index cc9ba993e..ffb3472 100644 --- a/third_party/blink/web_tests/fast/mediastream/constructors-expected.txt +++ b/third_party/blink/web_tests/fast/mediastream/constructors-expected.txt
@@ -8,7 +8,7 @@ PASS RTCPeerConnection() threw exception TypeError: Failed to construct 'RTCPeerConnection': Please use the 'new' operator, this DOM object constructor cannot be called as a function.. PASS RTCSessionDescription() threw exception TypeError: Failed to construct 'RTCSessionDescription': Please use the 'new' operator, this DOM object constructor cannot be called as a function.. PASS RTCIceCandidate() threw exception TypeError: Failed to construct 'RTCIceCandidate': Please use the 'new' operator, this DOM object constructor cannot be called as a function.. -PASS new RTCPeerConnection({iceServers:[{url:'stun://foobar.com:12345'}]}, null); did not throw exception. +PASS new RTCPeerConnection({iceServers:[{url:'stun:foobar.com:12345'}]}, null); did not throw exception. PASS new RTCSessionDescription({type:'offer',sdp:'foobar'}); did not throw exception. PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/mediastream/constructors.html b/third_party/blink/web_tests/fast/mediastream/constructors.html index 9bedcdc..32c74c95 100644 --- a/third_party/blink/web_tests/fast/mediastream/constructors.html +++ b/third_party/blink/web_tests/fast/mediastream/constructors.html
@@ -17,7 +17,7 @@ shouldThrow("RTCSessionDescription()"); shouldThrow("RTCIceCandidate()"); -shouldNotThrow("new RTCPeerConnection({iceServers:[{url:'stun://foobar.com:12345'}]}, null);"); +shouldNotThrow("new RTCPeerConnection({iceServers:[{url:'stun:foobar.com:12345'}]}, null);"); shouldNotThrow("new RTCSessionDescription({type:'offer',sdp:'foobar'});"); window.jsTestIsAsync = false;
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-navigation.js b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-navigation.js index dea56b3..72468a2 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-navigation.js +++ b/third_party/blink/web_tests/http/tests/devtools/console/viewport-testing/console-key-navigation.js
@@ -213,8 +213,8 @@ name += '#' + element.id; if (element.getAttribute('aria-label')) name += ':' + element.getAttribute('aria-label'); - else if (element.title) - name += ':' + element.title; + else if (UI.Tooltip.getContent(element)) + name += ':' + UI.Tooltip.getContent(element); else if (element.textContent && element.textContent.length < 50) { name += ':' + element.textContent.replace('\u200B', ''); } else if (element.className)
diff --git a/third_party/blink/web_tests/http/tests/workers/deprecation-report-crash.html b/third_party/blink/web_tests/http/tests/workers/deprecation-report-crash.html new file mode 100644 index 0000000..613e2f0 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/workers/deprecation-report-crash.html
@@ -0,0 +1,13 @@ +<!doctype html> +<html> +<script src = "/resources/testharness.js"></script> +<script src = "/resources/testharnessreport.js"></script> +<script> +// This is a regression test for https://crbug.com/1146824. +async_test((t) => { + const worker = new Worker('\n/path<', {type: 'module'}); + + worker.onerror = () => t.done(); +}, 'Creating a worker should not crash.'); +</script> +</html>
diff --git a/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver.html b/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver.html deleted file mode 100644 index f35279b..0000000 --- a/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver.html +++ /dev/null
@@ -1,15 +0,0 @@ -<!DOCTYPE html> -<body> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script> - -// navigator.webdriver property is a runtime enabled feature -// that should not exist if not excplicitly enabled -test(function() { - assert_false("webdriver" in window.navigator); - assert_true(navigator.webdriver === undefined); -}, "Test if webdriver property is not in the prototype chain"); -</script> -</body> -</html>
diff --git a/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver_enabled.html b/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver_enabled.html index 0ab4451..52060fd 100644 --- a/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver_enabled.html +++ b/third_party/blink/web_tests/navigator_webdriver/navigator_webdriver_enabled.html
@@ -10,6 +10,10 @@ "This test only works when run as a layout test!"); }, "Prerequisites to running the rest of the tests"); +test(function () { + assert_false(window.navigator.webdriver); +}, "Test if navigator.webdriver is false without automation"); + internals.runtimeFlags.automationControlledEnabled = true; test(function() {
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index 5b3ba57..a96554f0 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_mediaDevices.ondevicechange is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index 9df7a26a..afb062d 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_mediaDevices.ondevicechange is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index 7ab8cf1..8f86d40 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -32,6 +32,7 @@ PASS window.cached_navigator.userAgent is '' PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' +PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_mediaDevices.ondevicechange is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index fcf2bb4f3..f683cb6 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -57,6 +57,7 @@ PASS oldChildWindow.navigator.userAgent is newChildWindow.navigator.userAgent PASS oldChildWindow.navigator.vendor is newChildWindow.navigator.vendor PASS oldChildWindow.navigator.vendorSub is newChildWindow.navigator.vendorSub +PASS oldChildWindow.navigator.webdriver is newChildWindow.navigator.webdriver PASS oldChildWindow.navigator.xr.ondevicechange is newChildWindow.navigator.xr.ondevicechange PASS oldChildWindow.onabort is newChildWindow.onabort PASS oldChildWindow.onafterprint is newChildWindow.onafterprint
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index 1f6025be..1eb4e2e 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -33,6 +33,7 @@ PASS childWindow.navigator.userAgent is '' PASS childWindow.navigator.vendor is window.navigator.vendor PASS childWindow.navigator.vendorSub is '' +PASS childWindow.navigator.webdriver is false PASS childWindow.onabort is null PASS childWindow.onafterprint is null PASS childWindow.onanimationend is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index e6f27d0..e3dc9b3 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -33,6 +33,7 @@ PASS childWindow.navigator.userAgent is '' PASS childWindow.navigator.vendor is window.navigator.vendor PASS childWindow.navigator.vendorSub is '' +PASS childWindow.navigator.webdriver is false PASS childWindow.onabort is null PASS childWindow.onafterprint is null PASS childWindow.onanimationend is null
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 47b642e..ea48c46 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4582,6 +4582,7 @@ getter vendor getter vendorSub getter wakeLock + getter webdriver getter webkitPersistentStorage getter webkitTemporaryStorage getter xr
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 112ba8e..24630333 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5481,6 +5481,7 @@ getter vendorSub getter virtualKeyboard getter wakeLock + getter webdriver getter webkitPersistentStorage getter webkitTemporaryStorage getter xr
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium index 98d02b9..cc943454 100644 --- a/third_party/freetype/README.chromium +++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@ Name: FreeType URL: http://www.freetype.org/ -Version: VER-2-10-4-17-g3facafa44 -Revision: 3facafa44e2ac49ac15359bf6c83110614a6cbf7 +Version: VER-2-10-4-18-g56c610b14 +Revision: 56c610b145212b7acfb24a17e86fc0ba15aa3052 CPEPrefix: cpe:/a:freetype:freetype:2.10.1 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4ca5101..72bf461 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -6653,6 +6653,7 @@ <int value="236" label="ASGH_ASSOCIATED_INTERFACE_REQUEST"/> <int value="237" label="ASGH_RECEIVED_CONTROL_MESSAGE"/> <int value="238" label="CSDH_BAD_OWNER"/> + <int value="239" label="SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID"/> </enum> <enum name="BadMessageReasonExtensions"> @@ -16770,6 +16771,7 @@ <int value="37" label="showWebVitalsInPerformancePanel"/> <int value="38" label="recorder"/> <int value="39" label="APCA"/> + <int value="40" label="cspViolationsView"/> </enum> <enum name="DevToolsGridOverlayOpenedFrom">
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml index f662d44..b7e25d5 100644 --- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -554,7 +554,7 @@ </histogram> <histogram name="Accessibility.LanguageDetection.PercentageLanguageDetected" - units="%" expires_after="2020-12-01"> + units="%" expires_after="2021-05-23"> <owner>chrishall@chromium.org</owner> <owner>aboxhall@chromium.org</owner> <owner>dmazzoni@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml index ed8eb39..de72b54 100644 --- a/tools/metrics/histograms/histograms_xml/event/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -1640,6 +1640,16 @@ </summary> </histogram> +<histogram name="Event.WaylandDragDrop.IncomingDataTransferTime" units="ms" + expires_after="M90"> + <owner>rjkroege@chromium.org</owner> + <owner>adunaev@igalia.com</owner> + <summary> + Delay between the drag coming into the window and the window is actually + notified. + </summary> +</histogram> + <histogram base="true" name="EventLatency" units="microseconds" expires_after="2021-05-09"> <owner>mohsen@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index 2798f7ec..8b950d1 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -12560,7 +12560,7 @@ </histogram> <histogram name="Rollback.RollbackSaveResult" - enum="Rollback_RollbackSaveResult" expires_after="2021-01-01"> + enum="Rollback_RollbackSaveResult" expires_after="2021-03-01"> <owner>mpolzer@google.com</owner> <owner>managed-platforms@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml index 88735461..18f878f 100644 --- a/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/update_engine/histograms.xml
@@ -377,7 +377,7 @@ </histogram> <histogram name="UpdateEngine.EnterpriseRollback.Failure" - enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-01-01"> + enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-03-01"> <owner>mpolzer@google.com</owner> <owner>managed-platforms@google.com</owner> <summary> @@ -395,7 +395,7 @@ </histogram> <histogram name="UpdateEngine.EnterpriseRollback.Success" - enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-01-01"> + enum="UpdateEngineChromeOsVersionPrefix" expires_after="2021-03-01"> <owner>mpolzer@google.com</owner> <owner>managed-platforms@google.com</owner> <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index bcbea7b..b2d4514a 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -5907,6 +5907,19 @@ </metric> </event> +<event name="InstalledRelatedApps"> + <owner>rayankans@chromium.org</owner> + <owner>peter@chromium.org</owner> + <summary> + Recorded before resolving a call to navigator.getInstalledRelatedApps(). + </summary> + <metric name="Called"> + <summary> + Always true. + </summary> + </metric> +</event> + <event name="Intervention.DocumentWrite.ScriptBlock" singular="True"> <owner>bmcquade@chromium.org</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 96d077fa..3a2e2f8e 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,11 +6,11 @@ }, "mac": { "hash": "23c054de3c5738695431f962b9f5e79a888eb135", - "remote_path": "perfetto_binaries/trace_processor_shell/mac/254ea334b65f8a7d5d4ab087f861df0572fa6af7/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/mac/ca8783182d27a2fd1ae1212c6c75be922f42a840/trace_processor_shell" }, "linux": { "hash": "68451064b202f0b800ab6a86da1cdeb450fe5745", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/254ea334b65f8a7d5d4ab087f861df0572fa6af7/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/linux/ca8783182d27a2fd1ae1212c6c75be922f42a840/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/page_sets/update_webrtc_cases b/tools/perf/page_sets/update_webrtc_cases index 32eb7f6..35ac6913 100755 --- a/tools/perf/page_sets/update_webrtc_cases +++ b/tools/perf/page_sets/update_webrtc_cases
@@ -25,31 +25,26 @@ 'src/multiple-peerconnections', 'src/pause-play', ], - 'revision': '9f0ff9343a38dbf16199a964a18d7411d940c601', + 'revision': '63a46f73c917ffcdf765bd11622b10bf473eb11c', }, 'samples': { 'dirs': [ 'src/content/datachannel/datatransfer', 'src/content/getusermedia/resolution', - 'src/content/peerconnection/audio', ], - 'files': [ - 'src/js/common.js', - ], - 'revision': '6f9a14c10ee9b990d56c309d86d4b9129a4aa626', + 'revision': 'a4ca7fbc92825b4993d9a7fa1844206e0c718454', }, 'adapter': { 'files': [ - 'release/adapter.js', + 'adapter-latest.js', ], - 'revision': '5b7ce4bdce79b9cb754fe27b097106e9491e0354', + 'revision': 'bc3f52c57baaae789df6965c43f418cc995a9edb', }, } ADDED_SCRIPT_TAGS = ( '<script src="%s.js"></script>\n' - '<script src="adapter.js"></script>\n' - '<script src="common.js"></script>\n' + '<script src="adapter-latest.js"></script>\n' '</body></html>' ) @@ -122,7 +117,7 @@ ' * Deletes the <meta> tags.\n' ' * Discards the CSS files and corresponding link tags.\n' ' * Discards the JS files and corresponding script tags except for ' - 'main.js, adapter.js and common.js.\n' + 'main.js and adapter-latest.js.\n' ' * Renames the index.html and main.js files for each test to ' 'testname.html and testname.js.'))
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py index 171d9421..bbf19e8 100644 --- a/tools/perf/page_sets/webrtc_cases.py +++ b/tools/perf/page_sets/webrtc_cases.py
@@ -51,21 +51,6 @@ description='Amount of data transferred by data channel in 10 seconds') -class AudioCall(WebrtcPage): - """Why: Sets up a WebRTC audio call.""" - - def __init__(self, page_set, codec, tags): - super(AudioCall, self).__init__( - url='file://webrtc_cases/audio.html?codec=%s' % codec, - name='audio_call_%s_10s' % codec.lower(), - page_set=page_set, tags=tags) - self.codec = codec - - def ExecuteTest(self, action_runner): - action_runner.ExecuteJavaScript('codecSelector.value="%s";' % self.codec) - action_runner.ClickElement('button[id="callButton"]') - action_runner.Wait(10) - class CanvasCapturePeerConnection(WebrtcPage): """Why: Sets up a canvas capture stream connection to a peer connection."""
diff --git a/tools/perf/page_sets/webrtc_cases/adapter-latest.js b/tools/perf/page_sets/webrtc_cases/adapter-latest.js new file mode 100644 index 0000000..a8a0aa7 --- /dev/null +++ b/tools/perf/page_sets/webrtc_cases/adapter-latest.js
@@ -0,0 +1,5628 @@ +/* + * Copyright 2017 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ + +'use strict'; + +var _adapter_factory = require('./adapter_factory.js'); + +var adapter = (0, _adapter_factory.adapterFactory)({ window: typeof window === 'undefined' ? undefined : window }); +module.exports = adapter; // this is the difference from adapter_core. + +},{"./adapter_factory.js":2}],2:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.adapterFactory = adapterFactory; + +var _utils = require('./utils'); + +var utils = _interopRequireWildcard(_utils); + +var _chrome_shim = require('./chrome/chrome_shim'); + +var chromeShim = _interopRequireWildcard(_chrome_shim); + +var _edge_shim = require('./edge/edge_shim'); + +var edgeShim = _interopRequireWildcard(_edge_shim); + +var _firefox_shim = require('./firefox/firefox_shim'); + +var firefoxShim = _interopRequireWildcard(_firefox_shim); + +var _safari_shim = require('./safari/safari_shim'); + +var safariShim = _interopRequireWildcard(_safari_shim); + +var _common_shim = require('./common_shim'); + +var commonShim = _interopRequireWildcard(_common_shim); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// Shimming starts here. +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +function adapterFactory() { + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + window = _ref.window; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + shimChrome: true, + shimFirefox: true, + shimEdge: true, + shimSafari: true + }; + + // Utils. + var logging = utils.log; + var browserDetails = utils.detectBrowser(window); + + var adapter = { + browserDetails: browserDetails, + commonShim: commonShim, + extractVersion: utils.extractVersion, + disableLog: utils.disableLog, + disableWarnings: utils.disableWarnings + }; + + // Shim browser if found. + switch (browserDetails.browser) { + case 'chrome': + if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { + logging('Chrome shim is not included in this adapter release.'); + return adapter; + } + if (browserDetails.version === null) { + logging('Chrome shim can not determine version, not shimming.'); + return adapter; + } + logging('adapter.js shimming chrome.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = chromeShim; + + chromeShim.shimGetUserMedia(window); + chromeShim.shimMediaStream(window); + chromeShim.shimPeerConnection(window); + chromeShim.shimOnTrack(window); + chromeShim.shimAddTrackRemoveTrack(window); + chromeShim.shimGetSendersWithDtmf(window); + chromeShim.shimGetStats(window); + chromeShim.shimSenderReceiverGetStats(window); + chromeShim.fixNegotiationNeeded(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + case 'firefox': + if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) { + logging('Firefox shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming firefox.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = firefoxShim; + + firefoxShim.shimGetUserMedia(window); + firefoxShim.shimPeerConnection(window); + firefoxShim.shimOnTrack(window); + firefoxShim.shimRemoveStream(window); + firefoxShim.shimSenderGetStats(window); + firefoxShim.shimReceiverGetStats(window); + firefoxShim.shimRTCDataChannel(window); + firefoxShim.shimAddTransceiver(window); + firefoxShim.shimGetParameters(window); + firefoxShim.shimCreateOffer(window); + firefoxShim.shimCreateAnswer(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'edge': + if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { + logging('MS edge shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming edge.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = edgeShim; + + edgeShim.shimGetUserMedia(window); + edgeShim.shimGetDisplayMedia(window); + edgeShim.shimPeerConnection(window); + edgeShim.shimReplaceTrack(window); + + // the edge shim implements the full RTCIceCandidate object. + + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'safari': + if (!safariShim || !options.shimSafari) { + logging('Safari shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming safari.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = safariShim; + + safariShim.shimRTCIceServerUrls(window); + safariShim.shimCreateOfferLegacy(window); + safariShim.shimCallbacksAPI(window); + safariShim.shimLocalStreamsAPI(window); + safariShim.shimRemoteStreamsAPI(window); + safariShim.shimTrackEventTransceiver(window); + safariShim.shimGetUserMedia(window); + safariShim.shimAudioContext(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + default: + logging('Unsupported browser!'); + break; + } + + return adapter; +} + +// Browser shims. + +},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimMediaStream = shimMediaStream; +exports.shimOnTrack = shimOnTrack; +exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf; +exports.shimGetStats = shimGetStats; +exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats; +exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative; +exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.fixNegotiationNeeded = fixNegotiationNeeded; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function shimMediaStream(window) { + window.MediaStream = window.MediaStream || window.webkitMediaStream; +} + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { + get: function get() { + return this._ontrack; + }, + set: function set(f) { + if (this._ontrack) { + this.removeEventListener('track', this._ontrack); + } + this.addEventListener('track', this._ontrack = f); + }, + + enumerable: true, + configurable: true + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + var _this = this; + + if (!this._ontrackpoly) { + this._ontrackpoly = function (e) { + // onaddstream does not fire when a track is added to an existing + // stream. But stream.onaddtrack is implemented so we use that. + e.stream.addEventListener('addtrack', function (te) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === te.track.id; + }); + } else { + receiver = { track: te.track }; + } + + var event = new Event('track'); + event.track = te.track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + e.stream.getTracks().forEach(function (track) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === track.id; + }); + } else { + receiver = { track: track }; + } + var event = new Event('track'); + event.track = track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + }; + this.addEventListener('addstream', this._ontrackpoly); + } + return origSetRemoteDescription.apply(this, arguments); + }; + } else { + // even if RTCRtpTransceiver is in window, it is only used and + // emitted in unified-plan. Unfortunately this means we need + // to unconditionally wrap the event. + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + if (!e.transceiver) { + Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); + } + return e; + }); + } +} + +function shimGetSendersWithDtmf(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { + var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) { + return { + track: track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; + }; + + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + var sender = origAddTrack.apply(this, arguments); + if (!sender) { + sender = shimSenderWithDtmf(this, track); + this._senders.push(sender); + } + return sender; + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + origRemoveTrack.apply(this, arguments); + var idx = this._senders.indexOf(sender); + if (idx !== -1) { + this._senders.splice(idx, 1); + } + }; + } + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this2 = this; + + this._senders = this._senders || []; + origAddStream.apply(this, [stream]); + stream.getTracks().forEach(function (track) { + _this2._senders.push(shimSenderWithDtmf(_this2, track)); + }); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this3 = this; + + this._senders = this._senders || []; + origRemoveStream.apply(this, [stream]); + + stream.getTracks().forEach(function (track) { + var sender = _this3._senders.find(function (s) { + return s.track === track; + }); + if (sender) { + // remove sender + _this3._senders.splice(_this3._senders.indexOf(sender), 1); + } + }); + }; + } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this4 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this4; + }); + return senders; + }; + + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = this._pc.createDTMFSender(this.track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } +} + +function shimGetStats(window) { + if (!window.RTCPeerConnection) { + return; + } + + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + var _this5 = this; + + var _arguments = Array.prototype.slice.call(arguments), + selector = _arguments[0], + onSucc = _arguments[1], + onErr = _arguments[2]; + + // If selector is a function then we are in the old style stats so just + // pass back the original getStats format to avoid breaking old users. + + + if (arguments.length > 0 && typeof selector === 'function') { + return origGetStats.apply(this, arguments); + } + + // When spec-style getStats is supported, return those when called with + // either no arguments or the selector argument is null. + if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { + return origGetStats.apply(this, []); + } + + var fixChromeStats_ = function fixChromeStats_(response) { + var standardReport = {}; + var reports = response.result(); + reports.forEach(function (report) { + var standardStats = { + id: report.id, + timestamp: report.timestamp, + type: { + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[report.type] || report.type + }; + report.names().forEach(function (name) { + standardStats[name] = report.stat(name); + }); + standardReport[standardStats.id] = standardStats; + }); + + return standardReport; + }; + + // shim getStats with maplike support + var makeMapStats = function makeMapStats(stats) { + return new Map(Object.keys(stats).map(function (key) { + return [key, stats[key]]; + })); + }; + + if (arguments.length >= 2) { + var successCallbackWrapper_ = function successCallbackWrapper_(response) { + onSucc(makeMapStats(fixChromeStats_(response))); + }; + + return origGetStats.apply(this, [successCallbackWrapper_, selector]); + } + + // promise-support + return new Promise(function (resolve, reject) { + origGetStats.apply(_this5, [function (response) { + resolve(makeMapStats(fixChromeStats_(response))); + }, reject]); + }).then(onSucc, onErr); + }; +} + +function shimSenderReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { + return; + } + + // shim sender stats. + if (!('getStats' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this6 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this6; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + var sender = this; + return this._pc.getStats().then(function (result) { + return ( + /* Note: this will include stats of all senders that + * send a track with the same id as sender.track as + * it is not possible to identify the RTCRtpSender. + */ + utils.filterStats(result, sender.track, true) + ); + }); + }; + } + + // shim receiver stats. + if (!('getStats' in window.RTCRtpReceiver.prototype)) { + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + var _this7 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this7; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + var receiver = this; + return this._pc.getStats().then(function (result) { + return utils.filterStats(result, receiver.track, false); + }); + }; + } + + if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { + return; + } + + // shim RTCPeerConnection.getStats(track). + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { + var track = arguments[0]; + var sender = void 0; + var receiver = void 0; + var err = void 0; + this.getSenders().forEach(function (s) { + if (s.track === track) { + if (sender) { + err = true; + } else { + sender = s; + } + } + }); + this.getReceivers().forEach(function (r) { + if (r.track === track) { + if (receiver) { + err = true; + } else { + receiver = r; + } + } + return r.track === track; + }); + if (err || sender && receiver) { + return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); + } else if (sender) { + return sender.getStats(); + } else if (receiver) { + return receiver.getStats(); + } + return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); + } + return origGetStats.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrackWithNative(window) { + // shim addTrack/removeTrack with native variants in order to make + // the interactions with legacy getLocalStreams behave as in other browsers. + // Keeps a mapping stream.id => [stream, rtpsenders...] + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + var _this8 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + return Object.keys(this._shimmedLocalStreams).map(function (streamId) { + return _this8._shimmedLocalStreams[streamId][0]; + }); + }; + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + if (!stream) { + return origAddTrack.apply(this, arguments); + } + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + var sender = origAddTrack.apply(this, arguments); + if (!this._shimmedLocalStreams[stream.id]) { + this._shimmedLocalStreams[stream.id] = [stream, sender]; + } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { + this._shimmedLocalStreams[stream.id].push(sender); + } + return sender; + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this9 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this9.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + var existingSenders = this.getSenders(); + origAddStream.apply(this, arguments); + var newSenders = this.getSenders().filter(function (newSender) { + return existingSenders.indexOf(newSender) === -1; + }); + this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + delete this._shimmedLocalStreams[stream.id]; + return origRemoveStream.apply(this, arguments); + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + var _this10 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + if (sender) { + Object.keys(this._shimmedLocalStreams).forEach(function (streamId) { + var idx = _this10._shimmedLocalStreams[streamId].indexOf(sender); + if (idx !== -1) { + _this10._shimmedLocalStreams[streamId].splice(idx, 1); + } + if (_this10._shimmedLocalStreams[streamId].length === 1) { + delete _this10._shimmedLocalStreams[streamId]; + } + }); + } + return origRemoveTrack.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrack(window) { + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { + return shimAddTrackRemoveTrackWithNative(window); + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + var _this11 = this; + + var nativeStreams = origGetLocalStreams.apply(this); + this._reverseStreams = this._reverseStreams || {}; + return nativeStreams.map(function (stream) { + return _this11._reverseStreams[stream.id]; + }); + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this12 = this; + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this12.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!this._reverseStreams[stream.id]) { + var newStream = new window.MediaStream(stream.getTracks()); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(this, [stream]); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + origRemoveStream.apply(this, [this._streams[stream.id] || stream]); + delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; + delete this._streams[stream.id]; + }; + + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + var _this13 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + var streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || !streams[0].getTracks().find(function (t) { + return t === track; + })) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); + } + + var alreadyExists = this.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + var oldStream = this._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + + // Trigger ONN async. + Promise.resolve().then(function () { + _this13.dispatchEvent(new Event('negotiationneeded')); + }); + } else { + var newStream = new window.MediaStream([track]); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + this.addStream(newStream); + } + return this.getSenders().find(function (s) { + return s.track === track; + }); + }; + + // replace the internal stream id with the external one and + // vice versa. + function replaceInternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + function replaceExternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + ['createOffer', 'createAnswer'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + var _this14 = this; + + var args = arguments; + var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; + if (isLegacyCall) { + return nativeMethod.apply(this, [function (description) { + var desc = replaceInternalStreamId(_this14, description); + args[0].apply(null, [desc]); + }, function (err) { + if (args[1]) { + args[1].apply(null, err); + } + }, arguments[2]]); + } + return nativeMethod.apply(this, arguments).then(function (description) { + return replaceInternalStreamId(_this14, description); + }); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + + var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { + if (!arguments.length || !arguments[0].type) { + return origSetLocalDescription.apply(this, arguments); + } + arguments[0] = replaceExternalStreamId(this, arguments[0]); + return origSetLocalDescription.apply(this, arguments); + }; + + // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier + + var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { + get: function get() { + var description = origLocalDescription.get.apply(this); + if (description.type === '') { + return description; + } + return replaceInternalStreamId(this, description); + } + }); + + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + var _this15 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + // We can not yet check for sender instanceof RTCRtpSender + // since we shim RTPSender. So we check if sender._pc is set. + if (!sender._pc) { + throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); + } + var isLocal = sender._pc === this; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + this._streams = this._streams || {}; + var stream = void 0; + Object.keys(this._streams).forEach(function (streamid) { + var hasTrack = _this15._streams[streamid].getTracks().find(function (track) { + return sender.track === track; + }); + if (hasTrack) { + stream = _this15._streams[streamid]; + } + }); + + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + this.removeStream(this._reverseStreams[stream.id]); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + this.dispatchEvent(new Event('negotiationneeded')); + } + }; +} + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.webkitRTCPeerConnection; + } + if (!window.RTCPeerConnection) { + return; + } + + var addIceCandidateNullSupported = window.RTCPeerConnection.prototype.addIceCandidate.length === 0; + + // shim implicit creation of RTCSessionDescription/RTCIceCandidate + if (browserDetails.version < 53) { + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + + // support for addIceCandidate(null or undefined) + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { + if (!addIceCandidateNullSupported && !arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + // Firefox 68+ emits and processes {candidate: "", ...}, ignore + // in older versions. Native support planned for Chrome M77. + if (browserDetails.version < 78 && arguments[0] && arguments[0].candidate === '') { + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; +} + +// Attempt to fix ONN in plan-b mode. +function fixNegotiationNeeded(window) { + var browserDetails = utils.detectBrowser(window); + utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) { + var pc = e.target; + if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') { + if (pc.signalingState !== 'stable') { + return; + } + } + return e; + }); +} + +},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, getSourceId) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + // getSourceId is a function that returns a promise resolving with + // the sourceId of the screen/window/tab to be shared. + if (typeof getSourceId !== 'function') { + console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + return getSourceId(constraints).then(function (sourceId) { + var widthSpecified = constraints.video && constraints.video.width; + var heightSpecified = constraints.video && constraints.video.height; + var frameRateSpecified = constraints.video && constraints.video.frameRate; + constraints.video = { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sourceId, + maxFrameRate: frameRateSpecified || 3 + } + }; + if (widthSpecified) { + constraints.video.mandatory.maxWidth = widthSpecified; + } + if (heightSpecified) { + constraints.video.mandatory.maxHeight = heightSpecified; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }); + }; +} + +},{}],5:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var logging = utils.log; + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (!navigator.mediaDevices) { + return; + } + + var browserDetails = utils.detectBrowser(window); + + var constraintsToChrome_ = function constraintsToChrome_(c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) !== 'object' || c.mandatory || c.optional) { + return c; + } + var cc = {}; + Object.keys(c).forEach(function (key) { + if (key === 'require' || key === 'advanced' || key === 'mediaSource') { + return; + } + var r = _typeof(c[key]) === 'object' ? c[key] : { ideal: c[key] }; + if (r.exact !== undefined && typeof r.exact === 'number') { + r.min = r.max = r.exact; + } + var oldname_ = function oldname_(prefix, name) { + if (prefix) { + return prefix + name.charAt(0).toUpperCase() + name.slice(1); + } + return name === 'deviceId' ? 'sourceId' : name; + }; + if (r.ideal !== undefined) { + cc.optional = cc.optional || []; + var oc = {}; + if (typeof r.ideal === 'number') { + oc[oldname_('min', key)] = r.ideal; + cc.optional.push(oc); + oc = {}; + oc[oldname_('max', key)] = r.ideal; + cc.optional.push(oc); + } else { + oc[oldname_('', key)] = r.ideal; + cc.optional.push(oc); + } + } + if (r.exact !== undefined && typeof r.exact !== 'number') { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_('', key)] = r.exact; + } else { + ['min', 'max'].forEach(function (mix) { + if (r[mix] !== undefined) { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_(mix, key)] = r[mix]; + } + }); + } + }); + if (c.advanced) { + cc.optional = (cc.optional || []).concat(c.advanced); + } + return cc; + }; + + var shimConstraints_ = function shimConstraints_(constraints, func) { + if (browserDetails.version >= 61) { + return func(constraints); + } + constraints = JSON.parse(JSON.stringify(constraints)); + if (constraints && _typeof(constraints.audio) === 'object') { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + constraints = JSON.parse(JSON.stringify(constraints)); + remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); + remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); + constraints.audio = constraintsToChrome_(constraints.audio); + } + if (constraints && _typeof(constraints.video) === 'object') { + // Shim facingMode for mobile & surface pro. + var face = constraints.video.facingMode; + face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof(face)) === 'object' ? face : { ideal: face }); + var getSupportedFacingModeLies = browserDetails.version < 66; + + if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { + delete constraints.video.facingMode; + var matches = void 0; + if (face.exact === 'environment' || face.ideal === 'environment') { + matches = ['back', 'rear']; + } else if (face.exact === 'user' || face.ideal === 'user') { + matches = ['front']; + } + if (matches) { + // Look for matches in label, or use last cam for back (typical). + return navigator.mediaDevices.enumerateDevices().then(function (devices) { + devices = devices.filter(function (d) { + return d.kind === 'videoinput'; + }); + var dev = devices.find(function (d) { + return matches.some(function (match) { + return d.label.toLowerCase().includes(match); + }); + }); + if (!dev && devices.length && matches.includes('back')) { + dev = devices[devices.length - 1]; // more likely the back cam + } + if (dev) { + constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId }; + } + constraints.video = constraintsToChrome_(constraints.video); + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }); + } + } + constraints.video = constraintsToChrome_(constraints.video); + } + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }; + + var shimError_ = function shimError_(e) { + if (browserDetails.version >= 64) { + return e; + } + return { + name: { + PermissionDeniedError: 'NotAllowedError', + PermissionDismissedError: 'NotAllowedError', + InvalidStateError: 'NotAllowedError', + DevicesNotFoundError: 'NotFoundError', + ConstraintNotSatisfiedError: 'OverconstrainedError', + TrackStartError: 'NotReadableError', + MediaDeviceFailedDueToShutdown: 'NotAllowedError', + MediaDeviceKillSwitchOn: 'NotAllowedError', + TabCaptureError: 'AbortError', + ScreenCaptureError: 'AbortError', + DeviceCaptureError: 'AbortError' + }[e.name] || e.name, + message: e.message, + constraint: e.constraint || e.constraintName, + toString: function toString() { + return this.name + (this.message && ': ') + this.message; + } + }; + }; + + var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) { + shimConstraints_(constraints, function (c) { + navigator.webkitGetUserMedia(c, onSuccess, function (e) { + if (onError) { + onError(shimError_(e)); + } + }); + }); + }; + navigator.getUserMedia = getUserMedia_.bind(navigator); + + // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia + // function which returns a Promise, it does not accept spec-style + // constraints. + if (navigator.mediaDevices.getUserMedia) { + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (cs) { + return shimConstraints_(cs, function (c) { + return origGetUserMedia(c).then(function (stream) { + if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { + stream.getTracks().forEach(function (track) { + track.stop(); + }); + throw new DOMException('', 'NotFoundError'); + } + return stream; + }, function (e) { + return Promise.reject(shimError_(e)); + }); + }); + }; + } +} + +},{"../utils.js":15}],6:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimRTCIceCandidate = shimRTCIceCandidate; +exports.shimMaxMessageSize = shimMaxMessageSize; +exports.shimSendThrowTypeError = shimSendThrowTypeError; +exports.shimConnectionState = shimConnectionState; +exports.removeAllowExtmapMixed = removeAllowExtmapMixed; + +var _sdp = require('sdp'); + +var _sdp2 = _interopRequireDefault(_sdp); + +var _utils = require('./utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function shimRTCIceCandidate(window) { + // foundation is arbitrarily chosen as an indicator for full support for + // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface + if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { + return; + } + + var NativeRTCIceCandidate = window.RTCIceCandidate; + window.RTCIceCandidate = function RTCIceCandidate(args) { + // Remove the a= which shouldn't be part of the candidate string. + if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { + args = JSON.parse(JSON.stringify(args)); + args.candidate = args.candidate.substr(2); + } + + if (args.candidate && args.candidate.length) { + // Augment the native candidate with the parsed fields. + var nativeCandidate = new NativeRTCIceCandidate(args); + var parsedCandidate = _sdp2.default.parseCandidate(args.candidate); + var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); + + // Add a serializer that does not serialize the extra attributes. + augmentedCandidate.toJSON = function toJSON() { + return { + candidate: augmentedCandidate.candidate, + sdpMid: augmentedCandidate.sdpMid, + sdpMLineIndex: augmentedCandidate.sdpMLineIndex, + usernameFragment: augmentedCandidate.usernameFragment + }; + }; + return augmentedCandidate; + } + return new NativeRTCIceCandidate(args); + }; + window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { + if (e.candidate) { + Object.defineProperty(e, 'candidate', { + value: new window.RTCIceCandidate(e.candidate), + writable: 'false' + }); + } + return e; + }); +} + +function shimMaxMessageSize(window) { + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + + if (!('sctp' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { + get: function get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + } + }); + } + + var sctpInDescription = function sctpInDescription(description) { + if (!description || !description.sdp) { + return false; + } + var sections = _sdp2.default.splitSections(description.sdp); + sections.shift(); + return sections.some(function (mediaSection) { + var mLine = _sdp2.default.parseMLine(mediaSection); + return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; + }); + }; + + var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) { + // TODO: Is there a better solution for detecting Firefox? + var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); + if (match === null || match.length < 2) { + return -1; + } + var version = parseInt(match[1], 10); + // Test for NaN (yes, this is ugly) + return version !== version ? -1 : version; + }; + + var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) { + // Every implementation we know can send at least 64 KiB. + // Note: Although Chrome is technically able to send up to 256 KiB, the + // data does not reach the other peer reliably. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 + var canSendMaxMessageSize = 65536; + if (browserDetails.browser === 'firefox') { + if (browserDetails.version < 57) { + if (remoteIsFirefox === -1) { + // FF < 57 will send in 16 KiB chunks using the deprecated PPID + // fragmentation. + canSendMaxMessageSize = 16384; + } else { + // However, other FF (and RAWRTC) can reassemble PPID-fragmented + // messages. Thus, supporting ~2 GiB when sending. + canSendMaxMessageSize = 2147483637; + } + } else if (browserDetails.version < 60) { + // Currently, all FF >= 57 will reset the remote maximum message size + // to the default value when a data channel is created at a later + // stage. :( + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; + } else { + // FF >= 60 supports sending ~2 GiB + canSendMaxMessageSize = 2147483637; + } + } + return canSendMaxMessageSize; + }; + + var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) { + // Note: 65536 bytes is the default value from the SDP spec. Also, + // every implementation we know supports receiving 65536 bytes. + var maxMessageSize = 65536; + + // FF 57 has a slightly incorrect default remote max message size, so + // we need to adjust it here to avoid a failure when sending. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 + if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { + maxMessageSize = 65535; + } + + var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:'); + if (match.length > 0) { + maxMessageSize = parseInt(match[0].substr(19), 10); + } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { + // If the maximum message size is not present in the remote SDP and + // both local and remote are Firefox, the remote peer can receive + // ~2 GiB. + maxMessageSize = 2147483637; + } + return maxMessageSize; + }; + + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + this._sctp = null; + // Chrome decided to not expose .sctp in plan-b mode. + // As usual, adapter.js has to do an 'ugly worakaround' + // to cover up the mess. + if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { + var _getConfiguration = this.getConfiguration(), + sdpSemantics = _getConfiguration.sdpSemantics; + + if (sdpSemantics === 'plan-b') { + Object.defineProperty(this, 'sctp', { + get: function get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + }, + + enumerable: true, + configurable: true + }); + } + } + + if (sctpInDescription(arguments[0])) { + // Check if the remote is FF. + var isFirefox = getRemoteFirefoxVersion(arguments[0]); + + // Get the maximum message size the local peer is capable of sending + var canSendMMS = getCanSendMaxMessageSize(isFirefox); + + // Get the maximum message size of the remote peer. + var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); + + // Determine final maximum message size + var maxMessageSize = void 0; + if (canSendMMS === 0 && remoteMMS === 0) { + maxMessageSize = Number.POSITIVE_INFINITY; + } else if (canSendMMS === 0 || remoteMMS === 0) { + maxMessageSize = Math.max(canSendMMS, remoteMMS); + } else { + maxMessageSize = Math.min(canSendMMS, remoteMMS); + } + + // Create a dummy RTCSctpTransport object and the 'maxMessageSize' + // attribute. + var sctp = {}; + Object.defineProperty(sctp, 'maxMessageSize', { + get: function get() { + return maxMessageSize; + } + }); + this._sctp = sctp; + } + + return origSetRemoteDescription.apply(this, arguments); + }; +} + +function shimSendThrowTypeError(window) { + if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { + return; + } + + // Note: Although Firefox >= 57 has a native implementation, the maximum + // message size can be reset for all data channels at a later stage. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + + function wrapDcSend(dc, pc) { + var origDataChannelSend = dc.send; + dc.send = function send() { + var data = arguments[0]; + var length = data.length || data.size || data.byteLength; + if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { + throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); + } + return origDataChannelSend.apply(dc, arguments); + }; + } + var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; + window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { + var dataChannel = origCreateDataChannel.apply(this, arguments); + wrapDcSend(dataChannel, this); + return dataChannel; + }; + utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) { + wrapDcSend(e.channel, e.target); + return e; + }); +} + +/* shims RTCConnectionState by pretending it is the same as iceConnectionState. + * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 + * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect + * since DTLS failures would be hidden. See + * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 + * for the Firefox tracking bug. + */ +function shimConnectionState(window) { + if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { + return; + } + var proto = window.RTCPeerConnection.prototype; + Object.defineProperty(proto, 'connectionState', { + get: function get() { + return { + completed: 'connected', + checking: 'connecting' + }[this.iceConnectionState] || this.iceConnectionState; + }, + + enumerable: true, + configurable: true + }); + Object.defineProperty(proto, 'onconnectionstatechange', { + get: function get() { + return this._onconnectionstatechange || null; + }, + set: function set(cb) { + if (this._onconnectionstatechange) { + this.removeEventListener('connectionstatechange', this._onconnectionstatechange); + delete this._onconnectionstatechange; + } + if (cb) { + this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); + } + }, + + enumerable: true, + configurable: true + }); + + ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) { + var origMethod = proto[method]; + proto[method] = function () { + if (!this._connectionstatechangepoly) { + this._connectionstatechangepoly = function (e) { + var pc = e.target; + if (pc._lastConnectionState !== pc.connectionState) { + pc._lastConnectionState = pc.connectionState; + var newEvent = new Event('connectionstatechange', e); + pc.dispatchEvent(newEvent); + } + return e; + }; + this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); + } + return origMethod.apply(this, arguments); + }; + }); +} + +function removeAllowExtmapMixed(window) { + /* remove a=extmap-allow-mixed for webrtc.org < M71 */ + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { + return; + } + if (browserDetails.browser === 'safari' && browserDetails.version >= 605) { + return; + } + var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { + if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { + desc.sdp = desc.sdp.split('\n').filter(function (line) { + return line.trim() !== 'a=extmap-allow-mixed'; + }).join('\n'); + } + return nativeSRD.apply(this, arguments); + }; +} + +},{"./utils":15,"sdp":17}],7:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimPeerConnection = shimPeerConnection; +exports.shimReplaceTrack = shimReplaceTrack; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +var _filtericeservers = require('./filtericeservers'); + +var _rtcpeerconnectionShim = require('rtcpeerconnection-shim'); + +var _rtcpeerconnectionShim2 = _interopRequireDefault(_rtcpeerconnectionShim); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if (window.RTCIceGatherer) { + if (!window.RTCIceCandidate) { + window.RTCIceCandidate = function RTCIceCandidate(args) { + return args; + }; + } + if (!window.RTCSessionDescription) { + window.RTCSessionDescription = function RTCSessionDescription(args) { + return args; + }; + } + // this adds an additional event listener to MediaStrackTrack that signals + // when a tracks enabled property was changed. Workaround for a bug in + // addStream, see below. No longer required in 15025+ + if (browserDetails.version < 15025) { + var origMSTEnabled = Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype, 'enabled'); + Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { + set: function set(value) { + origMSTEnabled.set.call(this, value); + var ev = new Event('enabled'); + ev.enabled = value; + this.dispatchEvent(ev); + } + }); + } + } + + // ORTC defines the DTMF sender a bit different. + // https://github.com/w3c/ortc/issues/714 + if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = new window.RTCDtmfSender(this); + } else if (this.track.kind === 'video') { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + // Edge currently only implements the RTCDtmfSender, not the + // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2* + if (window.RTCDtmfSender && !window.RTCDTMFSender) { + window.RTCDTMFSender = window.RTCDtmfSender; + } + + var RTCPeerConnectionShim = (0, _rtcpeerconnectionShim2.default)(window, browserDetails.version); + window.RTCPeerConnection = function RTCPeerConnection(config) { + if (config && config.iceServers) { + config.iceServers = (0, _filtericeservers.filterIceServers)(config.iceServers, browserDetails.version); + utils.log('ICE servers after filtering:', config.iceServers); + } + return new RTCPeerConnectionShim(config); + }; + window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype; +} + +function shimReplaceTrack(window) { + // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 + if (window.RTCRtpSender && !('replaceTrack' in window.RTCRtpSender.prototype)) { + window.RTCRtpSender.prototype.replaceTrack = window.RTCRtpSender.prototype.setTrack; + } +} + +},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.filterIceServers = filterIceServers; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// Edge does not like +// 1) stun: filtered after 14393 unless ?transport=udp is present +// 2) turn: that does not have all of turn:host:port?transport=udp +// 3) turn: with ipv6 addresses +// 4) turn: occurring muliple times +function filterIceServers(iceServers, edgeVersion) { + var hasTurn = false; + iceServers = JSON.parse(JSON.stringify(iceServers)); + return iceServers.filter(function (server) { + if (server && (server.urls || server.url)) { + var urls = server.urls || server.url; + if (server.url && !server.urls) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + } + var isString = typeof urls === 'string'; + if (isString) { + urls = [urls]; + } + urls = urls.filter(function (url) { + // filter STUN unconditionally. + if (url.indexOf('stun:') === 0) { + return false; + } + + var validTurn = url.startsWith('turn') && !url.startsWith('turn:[') && url.includes('transport=udp'); + if (validTurn && !hasTurn) { + hasTurn = true; + return true; + } + return validTurn && !hasTurn; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + }); +} + +},{"../utils":15}],9:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window) { + if (!('getDisplayMedia' in window.navigator)) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = window.navigator.getDisplayMedia.bind(window.navigator); +} + +},{}],10:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetUserMedia = shimGetUserMedia; +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + var shimError_ = function shimError_(e) { + return { + name: { PermissionDeniedError: 'NotAllowedError' }[e.name] || e.name, + message: e.message, + constraint: e.constraint, + toString: function toString() { + return this.name; + } + }; + }; + + // getUserMedia error shim. + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + return origGetUserMedia(c).catch(function (e) { + return Promise.reject(shimError_(e)); + }); + }; +} + +},{}],11:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimOnTrack = shimOnTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.shimSenderGetStats = shimSenderGetStats; +exports.shimReceiverGetStats = shimReceiverGetStats; +exports.shimRemoveStream = shimRemoveStream; +exports.shimRTCDataChannel = shimRTCDataChannel; +exports.shimAddTransceiver = shimAddTransceiver; +exports.shimGetParameters = shimGetParameters; +exports.shimCreateOffer = shimCreateOffer; +exports.shimCreateAnswer = shimCreateAnswer; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { + return; // probably media.peerconnection.enabled=false in about:config + } + if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.mozRTCPeerConnection; + } + + if (browserDetails.version < 53) { + // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + + // support for addIceCandidate(null or undefined) + // as well as ignoring {sdpMid, candidate: ""} + if (browserDetails.version < 68) { + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + // Firefox 68+ emits and processes {candidate: "", ...}, ignore + // in older versions. + if (arguments[0] && arguments[0].candidate === '') { + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; + } + + var modernStatsTypes = { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }; + + var nativeGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + var _arguments = Array.prototype.slice.call(arguments), + selector = _arguments[0], + onSucc = _arguments[1], + onErr = _arguments[2]; + + return nativeGetStats.apply(this, [selector || null]).then(function (stats) { + if (browserDetails.version < 53 && !onSucc) { + // Shim only promise getStats with spec-hyphens in type names + // Leave callback version alone; misc old uses of forEach before Map + try { + stats.forEach(function (stat) { + stat.type = modernStatsTypes[stat.type] || stat.type; + }); + } catch (e) { + if (e.name !== 'TypeError') { + throw e; + } + // Avoid TypeError: "type" is read-only, in old versions. 34-43ish + stats.forEach(function (stat, i) { + stats.set(i, Object.assign({}, stat, { + type: modernStatsTypes[stat.type] || stat.type + })); + }); + } + } + return stats; + }).then(onSucc, onErr); + }; +} + +function shimSenderGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { + return; + } + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); + }; +} + +function shimReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { + return; + } + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + var _this2 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this2; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + return this._pc.getStats(this.track); + }; +} + +function shimRemoveStream(window) { + if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { + return; + } + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this3 = this; + + utils.deprecated('removeStream', 'removeTrack'); + this.getSenders().forEach(function (sender) { + if (sender.track && stream.getTracks().includes(sender.track)) { + _this3.removeTrack(sender); + } + }); + }; +} + +function shimRTCDataChannel(window) { + // rename DataChannel to RTCDataChannel (native fix in FF60): + // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 + if (window.DataChannel && !window.RTCDataChannel) { + window.RTCDataChannel = window.DataChannel; + } +} + +function shimAddTransceiver(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; + if (origAddTransceiver) { + window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { + this.setParametersPromises = []; + var initParameters = arguments[1]; + var shouldPerformCheck = initParameters && 'sendEncodings' in initParameters; + if (shouldPerformCheck) { + // If sendEncodings params are provided, validate grammar + initParameters.sendEncodings.forEach(function (encodingParam) { + if ('rid' in encodingParam) { + var ridRegex = /^[a-z0-9]{0,16}$/i; + if (!ridRegex.test(encodingParam.rid)) { + throw new TypeError('Invalid RID value provided.'); + } + } + if ('scaleResolutionDownBy' in encodingParam) { + if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { + throw new RangeError('scale_resolution_down_by must be >= 1.0'); + } + } + if ('maxFramerate' in encodingParam) { + if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { + throw new RangeError('max_framerate must be >= 0.0'); + } + } + }); + } + var transceiver = origAddTransceiver.apply(this, arguments); + if (shouldPerformCheck) { + // Check if the init options were applied. If not we do this in an + // asynchronous way and save the promise reference in a global object. + // This is an ugly hack, but at the same time is way more robust than + // checking the sender parameters before and after the createOffer + // Also note that after the createoffer we are not 100% sure that + // the params were asynchronously applied so we might miss the + // opportunity to recreate offer. + var sender = transceiver.sender; + + var params = sender.getParameters(); + if (!('encodings' in params) || + // Avoid being fooled by patched getParameters() below. + params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) { + params.encodings = initParameters.sendEncodings; + sender.sendEncodings = initParameters.sendEncodings; + this.setParametersPromises.push(sender.setParameters(params).then(function () { + delete sender.sendEncodings; + }).catch(function () { + delete sender.sendEncodings; + })); + } + } + return transceiver; + }; + } +} + +function shimGetParameters(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCRtpSender)) { + return; + } + var origGetParameters = window.RTCRtpSender.prototype.getParameters; + if (origGetParameters) { + window.RTCRtpSender.prototype.getParameters = function getParameters() { + var params = origGetParameters.apply(this, arguments); + if (!('encodings' in params)) { + params.encodings = [].concat(this.sendEncodings || [{}]); + } + return params; + }; + } +} + +function shimCreateOffer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer() { + var _this4 = this, + _arguments2 = arguments; + + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(function () { + return origCreateOffer.apply(_this4, _arguments2); + }).finally(function () { + _this4.setParametersPromises = []; + }); + } + return origCreateOffer.apply(this, arguments); + }; +} + +function shimCreateAnswer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; + window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { + var _this5 = this, + _arguments3 = arguments; + + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(function () { + return origCreateAnswer.apply(_this5, _arguments3); + }).finally(function () { + _this5.setParametersPromises = []; + }); + } + return origCreateAnswer.apply(this, arguments); + }; +} + +},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, preferredMediaSource) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + if (!(constraints && constraints.video)) { + var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); + err.name = 'NotFoundError'; + // from https://heycam.github.io/webidl/#idl-DOMException-error-names + err.code = 8; + return Promise.reject(err); + } + if (constraints.video === true) { + constraints.video = { mediaSource: preferredMediaSource }; + } else { + constraints.video.mediaSource = preferredMediaSource; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }; +} + +},{}],13:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimGetUserMedia(window) { + var browserDetails = utils.detectBrowser(window); + var navigator = window && window.navigator; + var MediaStreamTrack = window && window.MediaStreamTrack; + + navigator.getUserMedia = function (constraints, onSuccess, onError) { + // Replace Firefox 44+'s deprecation warning with unprefixed version. + utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + }; + + if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + + var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); + remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeGetUserMedia(c); + }; + + if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { + var nativeGetSettings = MediaStreamTrack.prototype.getSettings; + MediaStreamTrack.prototype.getSettings = function () { + var obj = nativeGetSettings.apply(this, arguments); + remap(obj, 'mozAutoGainControl', 'autoGainControl'); + remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); + return obj; + }; + } + + if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { + var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; + MediaStreamTrack.prototype.applyConstraints = function (c) { + if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c, 'autoGainControl', 'mozAutoGainControl'); + remap(c, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeApplyConstraints.apply(this, [c]); + }; + } + } +} + +},{"../utils":15}],14:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimLocalStreamsAPI = shimLocalStreamsAPI; +exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI; +exports.shimCallbacksAPI = shimCallbacksAPI; +exports.shimGetUserMedia = shimGetUserMedia; +exports.shimConstraints = shimConstraints; +exports.shimRTCIceServerUrls = shimRTCIceServerUrls; +exports.shimTrackEventTransceiver = shimTrackEventTransceiver; +exports.shimCreateOfferLegacy = shimCreateOfferLegacy; +exports.shimAudioContext = shimAudioContext; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimLocalStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + if (!this._localStreams) { + this._localStreams = []; + } + return this._localStreams; + }; + } + if (!('addStream' in window.RTCPeerConnection.prototype)) { + var _addTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this = this; + + if (!this._localStreams) { + this._localStreams = []; + } + if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + // Try to emulate Chrome's behaviour of adding in audio-video order. + // Safari orders by track id. + stream.getAudioTracks().forEach(function (track) { + return _addTrack.call(_this, track, stream); + }); + stream.getVideoTracks().forEach(function (track) { + return _addTrack.call(_this, track, stream); + }); + }; + + window.RTCPeerConnection.prototype.addTrack = function addTrack(track) { + var _this2 = this; + + for (var _len = arguments.length, streams = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + streams[_key - 1] = arguments[_key]; + } + + if (streams) { + streams.forEach(function (stream) { + if (!_this2._localStreams) { + _this2._localStreams = [stream]; + } else if (!_this2._localStreams.includes(stream)) { + _this2._localStreams.push(stream); + } + }); + } + return _addTrack.apply(this, arguments); + }; + } + if (!('removeStream' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this3 = this; + + if (!this._localStreams) { + this._localStreams = []; + } + var index = this._localStreams.indexOf(stream); + if (index === -1) { + return; + } + this._localStreams.splice(index, 1); + var tracks = stream.getTracks(); + this.getSenders().forEach(function (sender) { + if (tracks.includes(sender.track)) { + _this3.removeTrack(sender); + } + }); + }; + } +} + +function shimRemoteStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { + return this._remoteStreams ? this._remoteStreams : []; + }; + } + if (!('onaddstream' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { + get: function get() { + return this._onaddstream; + }, + set: function set(f) { + var _this4 = this; + + if (this._onaddstream) { + this.removeEventListener('addstream', this._onaddstream); + this.removeEventListener('track', this._onaddstreampoly); + } + this.addEventListener('addstream', this._onaddstream = f); + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!_this4._remoteStreams) { + _this4._remoteStreams = []; + } + if (_this4._remoteStreams.includes(stream)) { + return; + } + _this4._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + _this4.dispatchEvent(event); + }); + }); + } + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + var pc = this; + if (!this._onaddstreampoly) { + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!pc._remoteStreams) { + pc._remoteStreams = []; + } + if (pc._remoteStreams.indexOf(stream) >= 0) { + return; + } + pc._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + pc.dispatchEvent(event); + }); + }); + } + return origSetRemoteDescription.apply(pc, arguments); + }; + } +} + +function shimCallbacksAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + var prototype = window.RTCPeerConnection.prototype; + var origCreateOffer = prototype.createOffer; + var origCreateAnswer = prototype.createAnswer; + var setLocalDescription = prototype.setLocalDescription; + var setRemoteDescription = prototype.setRemoteDescription; + var addIceCandidate = prototype.addIceCandidate; + + prototype.createOffer = function createOffer(successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = origCreateOffer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + prototype.createAnswer = function createAnswer(successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = origCreateAnswer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + var withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setLocalDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setLocalDescription = withCallback; + + withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setRemoteDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setRemoteDescription = withCallback; + + withCallback = function withCallback(candidate, successCallback, failureCallback) { + var promise = addIceCandidate.apply(this, [candidate]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.addIceCandidate = withCallback; +} + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + // shim not needed in Safari 12.1 + var mediaDevices = navigator.mediaDevices; + var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); + navigator.mediaDevices.getUserMedia = function (constraints) { + return _getUserMedia(shimConstraints(constraints)); + }; + } + + if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { + navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); + }.bind(navigator); + } +} + +function shimConstraints(constraints) { + if (constraints && constraints.video !== undefined) { + return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) }); + } + + return constraints; +} + +function shimRTCIceServerUrls(window) { + if (!window.RTCPeerConnection) { + return; + } + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + var OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + var newIceServers = []; + for (var i = 0; i < pcConfig.iceServers.length; i++) { + var server = pcConfig.iceServers[i]; + if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + delete server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + if ('generateCertificate' in OrigPeerConnection) { + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function get() { + return OrigPeerConnection.generateCertificate; + } + }); + } +} + +function shimTrackEventTransceiver(window) { + // Add event.transceiver member over deprecated event.receiver + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimCreateOfferLegacy(window) { + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { + if (offerOptions) { + if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { + // support bit values + offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; + } + var audioTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.receiver.track.kind === 'audio'; + }); + if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { + if (audioTransceiver.direction === 'sendrecv') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('sendonly'); + } else { + audioTransceiver.direction = 'sendonly'; + } + } else if (audioTransceiver.direction === 'recvonly') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('inactive'); + } else { + audioTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { + this.addTransceiver('audio'); + } + + if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { + // support bit values + offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; + } + var videoTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.receiver.track.kind === 'video'; + }); + if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { + if (videoTransceiver.direction === 'sendrecv') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('sendonly'); + } else { + videoTransceiver.direction = 'sendonly'; + } + } else if (videoTransceiver.direction === 'recvonly') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('inactive'); + } else { + videoTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { + this.addTransceiver('video'); + } + } + return origCreateOffer.apply(this, arguments); + }; +} + +function shimAudioContext(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || window.AudioContext) { + return; + } + window.AudioContext = window.webkitAudioContext; +} + +},{"../utils":15}],15:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extractVersion = extractVersion; +exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent; +exports.disableLog = disableLog; +exports.disableWarnings = disableWarnings; +exports.log = log; +exports.deprecated = deprecated; +exports.detectBrowser = detectBrowser; +exports.compactObject = compactObject; +exports.walkStats = walkStats; +exports.filterStats = filterStats; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var logDisabled_ = true; +var deprecationWarnings_ = true; + +/** + * Extract browser version out of the provided user agent string. + * + * @param {!string} uastring userAgent string. + * @param {!string} expr Regular expression used as match criteria. + * @param {!number} pos position in the version string to be returned. + * @return {!number} browser version. + */ +function extractVersion(uastring, expr, pos) { + var match = uastring.match(expr); + return match && match.length >= pos && parseInt(match[pos], 10); +} + +// Wraps the peerconnection event eventNameToWrap in a function +// which returns the modified event object (or false to prevent +// the event). +function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { + if (!window.RTCPeerConnection) { + return; + } + var proto = window.RTCPeerConnection.prototype; + var nativeAddEventListener = proto.addEventListener; + proto.addEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap) { + return nativeAddEventListener.apply(this, arguments); + } + var wrappedCallback = function wrappedCallback(e) { + var modifiedEvent = wrapper(e); + if (modifiedEvent) { + if (cb.handleEvent) { + cb.handleEvent(modifiedEvent); + } else { + cb(modifiedEvent); + } + } + }; + this._eventMap = this._eventMap || {}; + if (!this._eventMap[eventNameToWrap]) { + this._eventMap[eventNameToWrap] = new Map(); + } + this._eventMap[eventNameToWrap].set(cb, wrappedCallback); + return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); + }; + + var nativeRemoveEventListener = proto.removeEventListener; + proto.removeEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (!this._eventMap[eventNameToWrap].has(cb)) { + return nativeRemoveEventListener.apply(this, arguments); + } + var unwrappedCb = this._eventMap[eventNameToWrap].get(cb); + this._eventMap[eventNameToWrap].delete(cb); + if (this._eventMap[eventNameToWrap].size === 0) { + delete this._eventMap[eventNameToWrap]; + } + if (Object.keys(this._eventMap).length === 0) { + delete this._eventMap; + } + return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); + }; + + Object.defineProperty(proto, 'on' + eventNameToWrap, { + get: function get() { + return this['_on' + eventNameToWrap]; + }, + set: function set(cb) { + if (this['_on' + eventNameToWrap]) { + this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); + delete this['_on' + eventNameToWrap]; + } + if (cb) { + this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); + } + }, + + enumerable: true, + configurable: true + }); +} + +function disableLog(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + logDisabled_ = bool; + return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; +} + +/** + * Disable or enable deprecation warnings + * @param {!boolean} bool set to true to disable warnings. + */ +function disableWarnings(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + deprecationWarnings_ = !bool; + return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); +} + +function log() { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') { + if (logDisabled_) { + return; + } + if (typeof console !== 'undefined' && typeof console.log === 'function') { + console.log.apply(console, arguments); + } + } +} + +/** + * Shows a deprecation warning suggesting the modern and spec-compatible API. + */ +function deprecated(oldMethod, newMethod) { + if (!deprecationWarnings_) { + return; + } + console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); +} + +/** + * Browser detector. + * + * @return {object} result containing browser and version + * properties. + */ +function detectBrowser(window) { + // Returned result object. + var result = { browser: null, version: null }; + + // Fail early if it's not a browser + if (typeof window === 'undefined' || !window.navigator) { + result.browser = 'Not a browser.'; + return result; + } + + var navigator = window.navigator; + + + if (navigator.mozGetUserMedia) { + // Firefox. + result.browser = 'firefox'; + result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); + } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection && !window.RTCIceGatherer) { + // Chrome, Chromium, Webview, Opera. + // Version matches Chrome/WebRTC version. + // Chrome 74 removed webkitGetUserMedia on http as well so we need the + // more complicated fallback to webkitRTCPeerConnection. + result.browser = 'chrome'; + result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); + } else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { + // Edge. + result.browser = 'edge'; + result.version = extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2); + } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { + // Safari. + result.browser = 'safari'; + result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); + result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; + } else { + // Default fallthrough: not supported. + result.browser = 'Not a supported browser.'; + return result; + } + + return result; +} + +/** + * Checks if something is an object. + * + * @param {*} val The something you want to check. + * @return true if val is an object, false otherwise. + */ +function isObject(val) { + return Object.prototype.toString.call(val) === '[object Object]'; +} + +/** + * Remove all empty objects and undefined values + * from a nested object -- an enhanced and vanilla version + * of Lodash's `compact`. + */ +function compactObject(data) { + if (!isObject(data)) { + return data; + } + + return Object.keys(data).reduce(function (accumulator, key) { + var isObj = isObject(data[key]); + var value = isObj ? compactObject(data[key]) : data[key]; + var isEmptyObject = isObj && !Object.keys(value).length; + if (value === undefined || isEmptyObject) { + return accumulator; + } + return Object.assign(accumulator, _defineProperty({}, key, value)); + }, {}); +} + +/* iterates the stats graph recursively. */ +function walkStats(stats, base, resultSet) { + if (!base || resultSet.has(base.id)) { + return; + } + resultSet.set(base.id, base); + Object.keys(base).forEach(function (name) { + if (name.endsWith('Id')) { + walkStats(stats, stats.get(base[name]), resultSet); + } else if (name.endsWith('Ids')) { + base[name].forEach(function (id) { + walkStats(stats, stats.get(id), resultSet); + }); + } + }); +} + +/* filter getStats for a sender/receiver track. */ +function filterStats(result, track, outbound) { + var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; + var filteredResult = new Map(); + if (track === null) { + return filteredResult; + } + var trackStats = []; + result.forEach(function (value) { + if (value.type === 'track' && value.trackIdentifier === track.id) { + trackStats.push(value); + } + }); + trackStats.forEach(function (trackStat) { + result.forEach(function (stats) { + if (stats.type === streamStatsType && stats.trackId === trackStat.id) { + walkStats(result, stats, filteredResult); + } + }); + }); + return filteredResult; +} + +},{}],16:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ +'use strict'; + +var SDPUtils = require('sdp'); + +function fixStatsType(stat) { + return { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[stat.type] || stat.type; +} + +function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { + var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); + + // Map ICE parameters (ufrag, pwd) to SDP. + sdp += SDPUtils.writeIceParameters( + transceiver.iceGatherer.getLocalParameters()); + + // Map DTLS parameters to SDP. + sdp += SDPUtils.writeDtlsParameters( + transceiver.dtlsTransport.getLocalParameters(), + type === 'offer' ? 'actpass' : dtlsRole || 'active'); + + sdp += 'a=mid:' + transceiver.mid + '\r\n'; + + if (transceiver.rtpSender && transceiver.rtpReceiver) { + sdp += 'a=sendrecv\r\n'; + } else if (transceiver.rtpSender) { + sdp += 'a=sendonly\r\n'; + } else if (transceiver.rtpReceiver) { + sdp += 'a=recvonly\r\n'; + } else { + sdp += 'a=inactive\r\n'; + } + + if (transceiver.rtpSender) { + var trackId = transceiver.rtpSender._initialTrackId || + transceiver.rtpSender.track.id; + transceiver.rtpSender._initialTrackId = trackId; + // spec. + var msid = 'msid:' + (stream ? stream.id : '-') + ' ' + + trackId + '\r\n'; + sdp += 'a=' + msid; + // for Chrome. Legacy should no longer be required. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' ' + msid; + + // RTX + if (transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' ' + msid; + sdp += 'a=ssrc-group:FID ' + + transceiver.sendEncodingParameters[0].ssrc + ' ' + + transceiver.sendEncodingParameters[0].rtx.ssrc + + '\r\n'; + } + } + // FIXME: this should be written by writeRtpDescription. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + } + return sdp; +} + +// Edge does not like +// 1) stun: filtered after 14393 unless ?transport=udp is present +// 2) turn: that does not have all of turn:host:port?transport=udp +// 3) turn: with ipv6 addresses +// 4) turn: occurring muliple times +function filterIceServers(iceServers, edgeVersion) { + var hasTurn = false; + iceServers = JSON.parse(JSON.stringify(iceServers)); + return iceServers.filter(function(server) { + if (server && (server.urls || server.url)) { + var urls = server.urls || server.url; + if (server.url && !server.urls) { + console.warn('RTCIceServer.url is deprecated! Use urls instead.'); + } + var isString = typeof urls === 'string'; + if (isString) { + urls = [urls]; + } + urls = urls.filter(function(url) { + var validTurn = url.indexOf('turn:') === 0 && + url.indexOf('transport=udp') !== -1 && + url.indexOf('turn:[') === -1 && + !hasTurn; + + if (validTurn) { + hasTurn = true; + return true; + } + return url.indexOf('stun:') === 0 && edgeVersion >= 14393 && + url.indexOf('?transport=udp') === -1; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + }); +} + +// Determines the intersection of local and remote capabilities. +function getCommonCapabilities(localCapabilities, remoteCapabilities) { + var commonCapabilities = { + codecs: [], + headerExtensions: [], + fecMechanisms: [] + }; + + var findCodecByPayloadType = function(pt, codecs) { + pt = parseInt(pt, 10); + for (var i = 0; i < codecs.length; i++) { + if (codecs[i].payloadType === pt || + codecs[i].preferredPayloadType === pt) { + return codecs[i]; + } + } + }; + + var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { + var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); + var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); + return lCodec && rCodec && + lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); + }; + + localCapabilities.codecs.forEach(function(lCodec) { + for (var i = 0; i < remoteCapabilities.codecs.length; i++) { + var rCodec = remoteCapabilities.codecs[i]; + if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && + lCodec.clockRate === rCodec.clockRate) { + if (lCodec.name.toLowerCase() === 'rtx' && + lCodec.parameters && rCodec.parameters.apt) { + // for RTX we need to find the local rtx that has a apt + // which points to the same local codec as the remote one. + if (!rtxCapabilityMatches(lCodec, rCodec, + localCapabilities.codecs, remoteCapabilities.codecs)) { + continue; + } + } + rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy + // number of channels is the highest common number of channels + rCodec.numChannels = Math.min(lCodec.numChannels, + rCodec.numChannels); + // push rCodec so we reply with offerer payload type + commonCapabilities.codecs.push(rCodec); + + // determine common feedback mechanisms + rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { + for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { + if (lCodec.rtcpFeedback[j].type === fb.type && + lCodec.rtcpFeedback[j].parameter === fb.parameter) { + return true; + } + } + return false; + }); + // FIXME: also need to determine .parameters + // see https://github.com/openpeer/ortc/issues/569 + break; + } + } + }); + + localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { + for (var i = 0; i < remoteCapabilities.headerExtensions.length; + i++) { + var rHeaderExtension = remoteCapabilities.headerExtensions[i]; + if (lHeaderExtension.uri === rHeaderExtension.uri) { + commonCapabilities.headerExtensions.push(rHeaderExtension); + break; + } + } + }); + + // FIXME: fecMechanisms + return commonCapabilities; +} + +// is action=setLocalDescription with type allowed in signalingState +function isActionAllowedInSignalingState(action, type, signalingState) { + return { + offer: { + setLocalDescription: ['stable', 'have-local-offer'], + setRemoteDescription: ['stable', 'have-remote-offer'] + }, + answer: { + setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], + setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] + } + }[type][action].indexOf(signalingState) !== -1; +} + +function maybeAddCandidate(iceTransport, candidate) { + // Edge's internal representation adds some fields therefore + // not all fieldѕ are taken into account. + var alreadyAdded = iceTransport.getRemoteCandidates() + .find(function(remoteCandidate) { + return candidate.foundation === remoteCandidate.foundation && + candidate.ip === remoteCandidate.ip && + candidate.port === remoteCandidate.port && + candidate.priority === remoteCandidate.priority && + candidate.protocol === remoteCandidate.protocol && + candidate.type === remoteCandidate.type; + }); + if (!alreadyAdded) { + iceTransport.addRemoteCandidate(candidate); + } + return !alreadyAdded; +} + + +function makeError(name, description) { + var e = new Error(description); + e.name = name; + // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names + e.code = { + NotSupportedError: 9, + InvalidStateError: 11, + InvalidAccessError: 15, + TypeError: undefined, + OperationError: undefined + }[name]; + return e; +} + +module.exports = function(window, edgeVersion) { + // https://w3c.github.io/mediacapture-main/#mediastream + // Helper function to add the track to the stream and + // dispatch the event ourselves. + function addTrackToStreamAndFireEvent(track, stream) { + stream.addTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', + {track: track})); + } + + function removeTrackFromStreamAndFireEvent(track, stream) { + stream.removeTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', + {track: track})); + } + + function fireAddTrack(pc, track, receiver, streams) { + var trackEvent = new Event('track'); + trackEvent.track = track; + trackEvent.receiver = receiver; + trackEvent.transceiver = {receiver: receiver}; + trackEvent.streams = streams; + window.setTimeout(function() { + pc._dispatchEvent('track', trackEvent); + }); + } + + var RTCPeerConnection = function(config) { + var pc = this; + + var _eventTarget = document.createDocumentFragment(); + ['addEventListener', 'removeEventListener', 'dispatchEvent'] + .forEach(function(method) { + pc[method] = _eventTarget[method].bind(_eventTarget); + }); + + this.canTrickleIceCandidates = null; + + this.needNegotiation = false; + + this.localStreams = []; + this.remoteStreams = []; + + this._localDescription = null; + this._remoteDescription = null; + + this.signalingState = 'stable'; + this.iceConnectionState = 'new'; + this.connectionState = 'new'; + this.iceGatheringState = 'new'; + + config = JSON.parse(JSON.stringify(config || {})); + + this.usingBundle = config.bundlePolicy === 'max-bundle'; + if (config.rtcpMuxPolicy === 'negotiate') { + throw(makeError('NotSupportedError', + 'rtcpMuxPolicy \'negotiate\' is not supported')); + } else if (!config.rtcpMuxPolicy) { + config.rtcpMuxPolicy = 'require'; + } + + switch (config.iceTransportPolicy) { + case 'all': + case 'relay': + break; + default: + config.iceTransportPolicy = 'all'; + break; + } + + switch (config.bundlePolicy) { + case 'balanced': + case 'max-compat': + case 'max-bundle': + break; + default: + config.bundlePolicy = 'balanced'; + break; + } + + config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); + + this._iceGatherers = []; + if (config.iceCandidatePoolSize) { + for (var i = config.iceCandidatePoolSize; i > 0; i--) { + this._iceGatherers.push(new window.RTCIceGatherer({ + iceServers: config.iceServers, + gatherPolicy: config.iceTransportPolicy + })); + } + } else { + config.iceCandidatePoolSize = 0; + } + + this._config = config; + + // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... + // everything that is needed to describe a SDP m-line. + this.transceivers = []; + + this._sdpSessionId = SDPUtils.generateSessionId(); + this._sdpSessionVersion = 0; + + this._dtlsRole = undefined; // role for a=setup to use in answers. + + this._isClosed = false; + }; + + Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', { + configurable: true, + get: function() { + return this._localDescription; + } + }); + Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', { + configurable: true, + get: function() { + return this._remoteDescription; + } + }); + + // set up event handlers on prototype + RTCPeerConnection.prototype.onicecandidate = null; + RTCPeerConnection.prototype.onaddstream = null; + RTCPeerConnection.prototype.ontrack = null; + RTCPeerConnection.prototype.onremovestream = null; + RTCPeerConnection.prototype.onsignalingstatechange = null; + RTCPeerConnection.prototype.oniceconnectionstatechange = null; + RTCPeerConnection.prototype.onconnectionstatechange = null; + RTCPeerConnection.prototype.onicegatheringstatechange = null; + RTCPeerConnection.prototype.onnegotiationneeded = null; + RTCPeerConnection.prototype.ondatachannel = null; + + RTCPeerConnection.prototype._dispatchEvent = function(name, event) { + if (this._isClosed) { + return; + } + this.dispatchEvent(event); + if (typeof this['on' + name] === 'function') { + this['on' + name](event); + } + }; + + RTCPeerConnection.prototype._emitGatheringStateChange = function() { + var event = new Event('icegatheringstatechange'); + this._dispatchEvent('icegatheringstatechange', event); + }; + + RTCPeerConnection.prototype.getConfiguration = function() { + return this._config; + }; + + RTCPeerConnection.prototype.getLocalStreams = function() { + return this.localStreams; + }; + + RTCPeerConnection.prototype.getRemoteStreams = function() { + return this.remoteStreams; + }; + + // internal helper to create a transceiver object. + // (which is not yet the same as the WebRTC 1.0 transceiver) + RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) { + var hasBundleTransport = this.transceivers.length > 0; + var transceiver = { + track: null, + iceGatherer: null, + iceTransport: null, + dtlsTransport: null, + localCapabilities: null, + remoteCapabilities: null, + rtpSender: null, + rtpReceiver: null, + kind: kind, + mid: null, + sendEncodingParameters: null, + recvEncodingParameters: null, + stream: null, + associatedRemoteMediaStreams: [], + wantReceive: true + }; + if (this.usingBundle && hasBundleTransport) { + transceiver.iceTransport = this.transceivers[0].iceTransport; + transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; + } else { + var transports = this._createIceAndDtlsTransports(); + transceiver.iceTransport = transports.iceTransport; + transceiver.dtlsTransport = transports.dtlsTransport; + } + if (!doNotAdd) { + this.transceivers.push(transceiver); + } + return transceiver; + }; + + RTCPeerConnection.prototype.addTrack = function(track, stream) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call addTrack on a closed peerconnection.'); + } + + var alreadyExists = this.transceivers.find(function(s) { + return s.track === track; + }); + + if (alreadyExists) { + throw makeError('InvalidAccessError', 'Track already exists.'); + } + + var transceiver; + for (var i = 0; i < this.transceivers.length; i++) { + if (!this.transceivers[i].track && + this.transceivers[i].kind === track.kind) { + transceiver = this.transceivers[i]; + } + } + if (!transceiver) { + transceiver = this._createTransceiver(track.kind); + } + + this._maybeFireNegotiationNeeded(); + + if (this.localStreams.indexOf(stream) === -1) { + this.localStreams.push(stream); + } + + transceiver.track = track; + transceiver.stream = stream; + transceiver.rtpSender = new window.RTCRtpSender(track, + transceiver.dtlsTransport); + return transceiver.rtpSender; + }; + + RTCPeerConnection.prototype.addStream = function(stream) { + var pc = this; + if (edgeVersion >= 15025) { + stream.getTracks().forEach(function(track) { + pc.addTrack(track, stream); + }); + } else { + // Clone is necessary for local demos mostly, attaching directly + // to two different senders does not work (build 10547). + // Fixed in 15025 (or earlier) + var clonedStream = stream.clone(); + stream.getTracks().forEach(function(track, idx) { + var clonedTrack = clonedStream.getTracks()[idx]; + track.addEventListener('enabled', function(event) { + clonedTrack.enabled = event.enabled; + }); + }); + clonedStream.getTracks().forEach(function(track) { + pc.addTrack(track, clonedStream); + }); + } + }; + + RTCPeerConnection.prototype.removeTrack = function(sender) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call removeTrack on a closed peerconnection.'); + } + + if (!(sender instanceof window.RTCRtpSender)) { + throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + + 'does not implement interface RTCRtpSender.'); + } + + var transceiver = this.transceivers.find(function(t) { + return t.rtpSender === sender; + }); + + if (!transceiver) { + throw makeError('InvalidAccessError', + 'Sender was not created by this connection.'); + } + var stream = transceiver.stream; + + transceiver.rtpSender.stop(); + transceiver.rtpSender = null; + transceiver.track = null; + transceiver.stream = null; + + // remove the stream from the set of local streams + var localStreams = this.transceivers.map(function(t) { + return t.stream; + }); + if (localStreams.indexOf(stream) === -1 && + this.localStreams.indexOf(stream) > -1) { + this.localStreams.splice(this.localStreams.indexOf(stream), 1); + } + + this._maybeFireNegotiationNeeded(); + }; + + RTCPeerConnection.prototype.removeStream = function(stream) { + var pc = this; + stream.getTracks().forEach(function(track) { + var sender = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (sender) { + pc.removeTrack(sender); + } + }); + }; + + RTCPeerConnection.prototype.getSenders = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpSender; + }) + .map(function(transceiver) { + return transceiver.rtpSender; + }); + }; + + RTCPeerConnection.prototype.getReceivers = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpReceiver; + }) + .map(function(transceiver) { + return transceiver.rtpReceiver; + }); + }; + + + RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, + usingBundle) { + var pc = this; + if (usingBundle && sdpMLineIndex > 0) { + return this.transceivers[0].iceGatherer; + } else if (this._iceGatherers.length) { + return this._iceGatherers.shift(); + } + var iceGatherer = new window.RTCIceGatherer({ + iceServers: this._config.iceServers, + gatherPolicy: this._config.iceTransportPolicy + }); + Object.defineProperty(iceGatherer, 'state', + {value: 'new', writable: true} + ); + + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = []; + this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { + var end = !event.candidate || Object.keys(event.candidate).length === 0; + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + iceGatherer.state = end ? 'completed' : 'gathering'; + if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) { + pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event); + } + }; + iceGatherer.addEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + return iceGatherer; + }; + + // start gathering from an RTCIceGatherer. + RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { + var pc = this; + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer.onlocalcandidate) { + return; + } + var bufferedCandidateEvents = + this.transceivers[sdpMLineIndex].bufferedCandidateEvents; + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null; + iceGatherer.removeEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + iceGatherer.onlocalcandidate = function(evt) { + if (pc.usingBundle && sdpMLineIndex > 0) { + // if we know that we use bundle we can drop candidates with + // ѕdpMLineIndex > 0. If we don't do this then our state gets + // confused since we dispose the extra ice gatherer. + return; + } + var event = new Event('icecandidate'); + event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; + + var cand = evt.candidate; + // Edge emits an empty object for RTCIceCandidateComplete‥ + var end = !cand || Object.keys(cand).length === 0; + if (end) { + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { + iceGatherer.state = 'completed'; + } + } else { + if (iceGatherer.state === 'new') { + iceGatherer.state = 'gathering'; + } + // RTCIceCandidate doesn't have a component, needs to be added + cand.component = 1; + // also the usernameFragment. TODO: update SDP to take both variants. + cand.ufrag = iceGatherer.getLocalParameters().usernameFragment; + + var serializedCandidate = SDPUtils.writeCandidate(cand); + event.candidate = Object.assign(event.candidate, + SDPUtils.parseCandidate(serializedCandidate)); + + event.candidate.candidate = serializedCandidate; + event.candidate.toJSON = function() { + return { + candidate: event.candidate.candidate, + sdpMid: event.candidate.sdpMid, + sdpMLineIndex: event.candidate.sdpMLineIndex, + usernameFragment: event.candidate.usernameFragment + }; + }; + } + + // update local description. + var sections = SDPUtils.getMediaSections(pc._localDescription.sdp); + if (!end) { + sections[event.candidate.sdpMLineIndex] += + 'a=' + event.candidate.candidate + '\r\n'; + } else { + sections[event.candidate.sdpMLineIndex] += + 'a=end-of-candidates\r\n'; + } + pc._localDescription.sdp = + SDPUtils.getDescription(pc._localDescription.sdp) + + sections.join(''); + var complete = pc.transceivers.every(function(transceiver) { + return transceiver.iceGatherer && + transceiver.iceGatherer.state === 'completed'; + }); + + if (pc.iceGatheringState !== 'gathering') { + pc.iceGatheringState = 'gathering'; + pc._emitGatheringStateChange(); + } + + // Emit candidate. Also emit null candidate when all gatherers are + // complete. + if (!end) { + pc._dispatchEvent('icecandidate', event); + } + if (complete) { + pc._dispatchEvent('icecandidate', new Event('icecandidate')); + pc.iceGatheringState = 'complete'; + pc._emitGatheringStateChange(); + } + }; + + // emit already gathered candidates. + window.setTimeout(function() { + bufferedCandidateEvents.forEach(function(e) { + iceGatherer.onlocalcandidate(e); + }); + }, 0); + }; + + // Create ICE transport and DTLS transport. + RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { + var pc = this; + var iceTransport = new window.RTCIceTransport(null); + iceTransport.onicestatechange = function() { + pc._updateIceConnectionState(); + pc._updateConnectionState(); + }; + + var dtlsTransport = new window.RTCDtlsTransport(iceTransport); + dtlsTransport.ondtlsstatechange = function() { + pc._updateConnectionState(); + }; + dtlsTransport.onerror = function() { + // onerror does not set state to failed by itself. + Object.defineProperty(dtlsTransport, 'state', + {value: 'failed', writable: true}); + pc._updateConnectionState(); + }; + + return { + iceTransport: iceTransport, + dtlsTransport: dtlsTransport + }; + }; + + // Destroy ICE gatherer, ICE transport and DTLS transport. + // Without triggering the callbacks. + RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( + sdpMLineIndex) { + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer) { + delete iceGatherer.onlocalcandidate; + delete this.transceivers[sdpMLineIndex].iceGatherer; + } + var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; + if (iceTransport) { + delete iceTransport.onicestatechange; + delete this.transceivers[sdpMLineIndex].iceTransport; + } + var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; + if (dtlsTransport) { + delete dtlsTransport.ondtlsstatechange; + delete dtlsTransport.onerror; + delete this.transceivers[sdpMLineIndex].dtlsTransport; + } + }; + + // Start the RTP Sender and Receiver for a transceiver. + RTCPeerConnection.prototype._transceive = function(transceiver, + send, recv) { + var params = getCommonCapabilities(transceiver.localCapabilities, + transceiver.remoteCapabilities); + if (send && transceiver.rtpSender) { + params.encodings = transceiver.sendEncodingParameters; + params.rtcp = { + cname: SDPUtils.localCName, + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.recvEncodingParameters.length) { + params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; + } + transceiver.rtpSender.send(params); + } + if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { + // remove RTX field in Edge 14942 + if (transceiver.kind === 'video' + && transceiver.recvEncodingParameters + && edgeVersion < 15019) { + transceiver.recvEncodingParameters.forEach(function(p) { + delete p.rtx; + }); + } + if (transceiver.recvEncodingParameters.length) { + params.encodings = transceiver.recvEncodingParameters; + } else { + params.encodings = [{}]; + } + params.rtcp = { + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.rtcpParameters.cname) { + params.rtcp.cname = transceiver.rtcpParameters.cname; + } + if (transceiver.sendEncodingParameters.length) { + params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; + } + transceiver.rtpReceiver.receive(params); + } + }; + + RTCPeerConnection.prototype.setLocalDescription = function(description) { + var pc = this; + + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + + if (!isActionAllowedInSignalingState('setLocalDescription', + description.type, pc.signalingState) || pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not set local ' + description.type + + ' in state ' + pc.signalingState)); + } + + var sections; + var sessionpart; + if (description.type === 'offer') { + // VERY limited support for SDP munging. Limited to: + // * changing the order of codecs + sections = SDPUtils.splitSections(description.sdp); + sessionpart = sections.shift(); + sections.forEach(function(mediaSection, sdpMLineIndex) { + var caps = SDPUtils.parseRtpParameters(mediaSection); + pc.transceivers[sdpMLineIndex].localCapabilities = caps; + }); + + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + pc._gather(transceiver.mid, sdpMLineIndex); + }); + } else if (description.type === 'answer') { + sections = SDPUtils.splitSections(pc._remoteDescription.sdp); + sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + sections.forEach(function(mediaSection, sdpMLineIndex) { + var transceiver = pc.transceivers[sdpMLineIndex]; + var iceGatherer = transceiver.iceGatherer; + var iceTransport = transceiver.iceTransport; + var dtlsTransport = transceiver.dtlsTransport; + var localCapabilities = transceiver.localCapabilities; + var remoteCapabilities = transceiver.remoteCapabilities; + + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; + + if (!rejected && !transceiver.rejected) { + var remoteIceParameters = SDPUtils.getIceParameters( + mediaSection, sessionpart); + var remoteDtlsParameters = SDPUtils.getDtlsParameters( + mediaSection, sessionpart); + if (isIceLite) { + remoteDtlsParameters.role = 'server'; + } + + if (!pc.usingBundle || sdpMLineIndex === 0) { + pc._gather(transceiver.mid, sdpMLineIndex); + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + isIceLite ? 'controlling' : 'controlled'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + // Calculate intersection of capabilities. + var params = getCommonCapabilities(localCapabilities, + remoteCapabilities); + + // Start the RTCRtpSender. The RTCRtpReceiver for this + // transceiver has already been started in setRemoteDescription. + pc._transceive(transceiver, + params.codecs.length > 0, + false); + } + }); + } + + pc._localDescription = { + type: description.type, + sdp: description.sdp + }; + if (description.type === 'offer') { + pc._updateSignalingState('have-local-offer'); + } else { + pc._updateSignalingState('stable'); + } + + return Promise.resolve(); + }; + + RTCPeerConnection.prototype.setRemoteDescription = function(description) { + var pc = this; + + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + + if (!isActionAllowedInSignalingState('setRemoteDescription', + description.type, pc.signalingState) || pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not set remote ' + description.type + + ' in state ' + pc.signalingState)); + } + + var streams = {}; + pc.remoteStreams.forEach(function(stream) { + streams[stream.id] = stream; + }); + var receiverList = []; + var sections = SDPUtils.splitSections(description.sdp); + var sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + var usingBundle = SDPUtils.matchPrefix(sessionpart, + 'a=group:BUNDLE ').length > 0; + pc.usingBundle = usingBundle; + var iceOptions = SDPUtils.matchPrefix(sessionpart, + 'a=ice-options:')[0]; + if (iceOptions) { + pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ') + .indexOf('trickle') >= 0; + } else { + pc.canTrickleIceCandidates = false; + } + + sections.forEach(function(mediaSection, sdpMLineIndex) { + var lines = SDPUtils.splitLines(mediaSection); + var kind = SDPUtils.getKind(mediaSection); + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; + var protocol = lines[0].substr(2).split(' ')[2]; + + var direction = SDPUtils.getDirection(mediaSection, sessionpart); + var remoteMsid = SDPUtils.parseMsid(mediaSection); + + var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); + + // Reject datachannels which are not implemented yet. + if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' || + protocol === 'UDP/DTLS/SCTP'))) { + // TODO: this is dangerous in the case where a non-rejected m-line + // becomes rejected. + pc.transceivers[sdpMLineIndex] = { + mid: mid, + kind: kind, + protocol: protocol, + rejected: true + }; + return; + } + + if (!rejected && pc.transceivers[sdpMLineIndex] && + pc.transceivers[sdpMLineIndex].rejected) { + // recycle a rejected transceiver. + pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true); + } + + var transceiver; + var iceGatherer; + var iceTransport; + var dtlsTransport; + var rtpReceiver; + var sendEncodingParameters; + var recvEncodingParameters; + var localCapabilities; + + var track; + // FIXME: ensure the mediaSection has rtcp-mux set. + var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); + var remoteIceParameters; + var remoteDtlsParameters; + if (!rejected) { + remoteIceParameters = SDPUtils.getIceParameters(mediaSection, + sessionpart); + remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, + sessionpart); + remoteDtlsParameters.role = 'client'; + } + recvEncodingParameters = + SDPUtils.parseRtpEncodingParameters(mediaSection); + + var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); + + var isComplete = SDPUtils.matchPrefix(mediaSection, + 'a=end-of-candidates', sessionpart).length > 0; + var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') + .map(function(cand) { + return SDPUtils.parseCandidate(cand); + }) + .filter(function(cand) { + return cand.component === 1; + }); + + // Check if we can use BUNDLE and dispose transports. + if ((description.type === 'offer' || description.type === 'answer') && + !rejected && usingBundle && sdpMLineIndex > 0 && + pc.transceivers[sdpMLineIndex]) { + pc._disposeIceAndDtlsTransports(sdpMLineIndex); + pc.transceivers[sdpMLineIndex].iceGatherer = + pc.transceivers[0].iceGatherer; + pc.transceivers[sdpMLineIndex].iceTransport = + pc.transceivers[0].iceTransport; + pc.transceivers[sdpMLineIndex].dtlsTransport = + pc.transceivers[0].dtlsTransport; + if (pc.transceivers[sdpMLineIndex].rtpSender) { + pc.transceivers[sdpMLineIndex].rtpSender.setTransport( + pc.transceivers[0].dtlsTransport); + } + if (pc.transceivers[sdpMLineIndex].rtpReceiver) { + pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( + pc.transceivers[0].dtlsTransport); + } + } + if (description.type === 'offer' && !rejected) { + transceiver = pc.transceivers[sdpMLineIndex] || + pc._createTransceiver(kind); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, + usingBundle); + } + + if (cands.length && transceiver.iceTransport.state === 'new') { + if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { + transceiver.iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); + + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + + sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 2) * 1001 + }]; + + // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams + var isNewTrack = false; + if (direction === 'sendrecv' || direction === 'sendonly') { + isNewTrack = !transceiver.rtpReceiver; + rtpReceiver = transceiver.rtpReceiver || + new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); + + if (isNewTrack) { + var stream; + track = rtpReceiver.track; + // FIXME: does not work with Plan B. + if (remoteMsid && remoteMsid.stream === '-') { + // no-op. a stream id of '-' means: no associated stream. + } else if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + Object.defineProperty(streams[remoteMsid.stream], 'id', { + get: function() { + return remoteMsid.stream; + } + }); + } + Object.defineProperty(track, 'id', { + get: function() { + return remoteMsid.track; + } + }); + stream = streams[remoteMsid.stream]; + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + stream = streams.default; + } + if (stream) { + addTrackToStreamAndFireEvent(track, stream); + transceiver.associatedRemoteMediaStreams.push(stream); + } + receiverList.push([track, rtpReceiver, stream]); + } + } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { + transceiver.associatedRemoteMediaStreams.forEach(function(s) { + var nativeTrack = s.getTracks().find(function(t) { + return t.id === transceiver.rtpReceiver.track.id; + }); + if (nativeTrack) { + removeTrackFromStreamAndFireEvent(nativeTrack, s); + } + }); + transceiver.associatedRemoteMediaStreams = []; + } + + transceiver.localCapabilities = localCapabilities; + transceiver.remoteCapabilities = remoteCapabilities; + transceiver.rtpReceiver = rtpReceiver; + transceiver.rtcpParameters = rtcpParameters; + transceiver.sendEncodingParameters = sendEncodingParameters; + transceiver.recvEncodingParameters = recvEncodingParameters; + + // Start the RTCRtpReceiver now. The RTPSender is started in + // setLocalDescription. + pc._transceive(pc.transceivers[sdpMLineIndex], + false, + isNewTrack); + } else if (description.type === 'answer' && !rejected) { + transceiver = pc.transceivers[sdpMLineIndex]; + iceGatherer = transceiver.iceGatherer; + iceTransport = transceiver.iceTransport; + dtlsTransport = transceiver.dtlsTransport; + rtpReceiver = transceiver.rtpReceiver; + sendEncodingParameters = transceiver.sendEncodingParameters; + localCapabilities = transceiver.localCapabilities; + + pc.transceivers[sdpMLineIndex].recvEncodingParameters = + recvEncodingParameters; + pc.transceivers[sdpMLineIndex].remoteCapabilities = + remoteCapabilities; + pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; + + if (cands.length && iceTransport.state === 'new') { + if ((isIceLite || isComplete) && + (!usingBundle || sdpMLineIndex === 0)) { + iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + if (!usingBundle || sdpMLineIndex === 0) { + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + 'controlling'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + // If the offer contained RTX but the answer did not, + // remove RTX from sendEncodingParameters. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + pc._transceive(transceiver, + direction === 'sendrecv' || direction === 'recvonly', + direction === 'sendrecv' || direction === 'sendonly'); + + // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams + if (rtpReceiver && + (direction === 'sendrecv' || direction === 'sendonly')) { + track = rtpReceiver.track; + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + } + addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); + receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + addTrackToStreamAndFireEvent(track, streams.default); + receiverList.push([track, rtpReceiver, streams.default]); + } + } else { + // FIXME: actually the receiver should be created later. + delete transceiver.rtpReceiver; + } + } + }); + + if (pc._dtlsRole === undefined) { + pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; + } + + pc._remoteDescription = { + type: description.type, + sdp: description.sdp + }; + if (description.type === 'offer') { + pc._updateSignalingState('have-remote-offer'); + } else { + pc._updateSignalingState('stable'); + } + Object.keys(streams).forEach(function(sid) { + var stream = streams[sid]; + if (stream.getTracks().length) { + if (pc.remoteStreams.indexOf(stream) === -1) { + pc.remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + window.setTimeout(function() { + pc._dispatchEvent('addstream', event); + }); + } + + receiverList.forEach(function(item) { + var track = item[0]; + var receiver = item[1]; + if (stream.id !== item[2].id) { + return; + } + fireAddTrack(pc, track, receiver, [stream]); + }); + } + }); + receiverList.forEach(function(item) { + if (item[2]) { + return; + } + fireAddTrack(pc, item[0], item[1], []); + }); + + // check whether addIceCandidate({}) was called within four seconds after + // setRemoteDescription. + window.setTimeout(function() { + if (!(pc && pc.transceivers)) { + return; + } + pc.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && + transceiver.iceTransport.state === 'new' && + transceiver.iceTransport.getRemoteCandidates().length > 0) { + console.warn('Timeout for addRemoteCandidate. Consider sending ' + + 'an end-of-candidates notification'); + transceiver.iceTransport.addRemoteCandidate({}); + } + }); + }, 4000); + + return Promise.resolve(); + }; + + RTCPeerConnection.prototype.close = function() { + this.transceivers.forEach(function(transceiver) { + /* not yet + if (transceiver.iceGatherer) { + transceiver.iceGatherer.close(); + } + */ + if (transceiver.iceTransport) { + transceiver.iceTransport.stop(); + } + if (transceiver.dtlsTransport) { + transceiver.dtlsTransport.stop(); + } + if (transceiver.rtpSender) { + transceiver.rtpSender.stop(); + } + if (transceiver.rtpReceiver) { + transceiver.rtpReceiver.stop(); + } + }); + // FIXME: clean up tracks, local streams, remote streams, etc + this._isClosed = true; + this._updateSignalingState('closed'); + }; + + // Update the signaling state. + RTCPeerConnection.prototype._updateSignalingState = function(newState) { + this.signalingState = newState; + var event = new Event('signalingstatechange'); + this._dispatchEvent('signalingstatechange', event); + }; + + // Determine whether to fire the negotiationneeded event. + RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { + var pc = this; + if (this.signalingState !== 'stable' || this.needNegotiation === true) { + return; + } + this.needNegotiation = true; + window.setTimeout(function() { + if (pc.needNegotiation) { + pc.needNegotiation = false; + var event = new Event('negotiationneeded'); + pc._dispatchEvent('negotiationneeded', event); + } + }, 0); + }; + + // Update the ice connection state. + RTCPeerConnection.prototype._updateIceConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + checking: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + } + }); + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.checking > 0) { + newState = 'checking'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0) { + newState = 'connected'; + } else if (states.completed > 0) { + newState = 'completed'; + } + + if (newState !== this.iceConnectionState) { + this.iceConnectionState = newState; + var event = new Event('iceconnectionstatechange'); + this._dispatchEvent('iceconnectionstatechange', event); + } + }; + + // Update the connection state. + RTCPeerConnection.prototype._updateConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + connecting: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && transceiver.dtlsTransport && + !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + states[transceiver.dtlsTransport.state]++; + } + }); + // ICETransport.completed and connected are the same for this purpose. + states.connected += states.completed; + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.connecting > 0) { + newState = 'connecting'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0) { + newState = 'connected'; + } + + if (newState !== this.connectionState) { + this.connectionState = newState; + var event = new Event('connectionstatechange'); + this._dispatchEvent('connectionstatechange', event); + } + }; + + RTCPeerConnection.prototype.createOffer = function() { + var pc = this; + + if (pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createOffer after close')); + } + + var numAudioTracks = pc.transceivers.filter(function(t) { + return t.kind === 'audio'; + }).length; + var numVideoTracks = pc.transceivers.filter(function(t) { + return t.kind === 'video'; + }).length; + + // Determine number of audio and video tracks we need to send/recv. + var offerOptions = arguments[0]; + if (offerOptions) { + // Reject Chrome legacy constraints. + if (offerOptions.mandatory || offerOptions.optional) { + throw new TypeError( + 'Legacy mandatory/optional constraints not supported.'); + } + if (offerOptions.offerToReceiveAudio !== undefined) { + if (offerOptions.offerToReceiveAudio === true) { + numAudioTracks = 1; + } else if (offerOptions.offerToReceiveAudio === false) { + numAudioTracks = 0; + } else { + numAudioTracks = offerOptions.offerToReceiveAudio; + } + } + if (offerOptions.offerToReceiveVideo !== undefined) { + if (offerOptions.offerToReceiveVideo === true) { + numVideoTracks = 1; + } else if (offerOptions.offerToReceiveVideo === false) { + numVideoTracks = 0; + } else { + numVideoTracks = offerOptions.offerToReceiveVideo; + } + } + } + + pc.transceivers.forEach(function(transceiver) { + if (transceiver.kind === 'audio') { + numAudioTracks--; + if (numAudioTracks < 0) { + transceiver.wantReceive = false; + } + } else if (transceiver.kind === 'video') { + numVideoTracks--; + if (numVideoTracks < 0) { + transceiver.wantReceive = false; + } + } + }); + + // Create M-lines for recvonly streams. + while (numAudioTracks > 0 || numVideoTracks > 0) { + if (numAudioTracks > 0) { + pc._createTransceiver('audio'); + numAudioTracks--; + } + if (numVideoTracks > 0) { + pc._createTransceiver('video'); + numVideoTracks--; + } + } + + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + // For each track, create an ice gatherer, ice transport, + // dtls transport, potentially rtpsender and rtpreceiver. + var track = transceiver.track; + var kind = transceiver.kind; + var mid = transceiver.mid || SDPUtils.generateIdentifier(); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, + pc.usingBundle); + } + + var localCapabilities = window.RTCRtpSender.getCapabilities(kind); + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + localCapabilities.codecs.forEach(function(codec) { + // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 + // by adding level-asymmetry-allowed=1 + if (codec.name === 'H264' && + codec.parameters['level-asymmetry-allowed'] === undefined) { + codec.parameters['level-asymmetry-allowed'] = '1'; + } + + // for subsequent offers, we might have to re-use the payload + // type of the last offer. + if (transceiver.remoteCapabilities && + transceiver.remoteCapabilities.codecs) { + transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) { + if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && + codec.clockRate === remoteCodec.clockRate) { + codec.preferredPayloadType = remoteCodec.payloadType; + } + }); + } + }); + localCapabilities.headerExtensions.forEach(function(hdrExt) { + var remoteExtensions = transceiver.remoteCapabilities && + transceiver.remoteCapabilities.headerExtensions || []; + remoteExtensions.forEach(function(rHdrExt) { + if (hdrExt.uri === rHdrExt.uri) { + hdrExt.id = rHdrExt.id; + } + }); + }); + + // generate an ssrc now, to be used later in rtpSender.send + var sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 1) * 1001 + }]; + if (track) { + // add RTX + if (edgeVersion >= 15019 && kind === 'video' && + !sendEncodingParameters[0].rtx) { + sendEncodingParameters[0].rtx = { + ssrc: sendEncodingParameters[0].ssrc + 1 + }; + } + } + + if (transceiver.wantReceive) { + transceiver.rtpReceiver = new window.RTCRtpReceiver( + transceiver.dtlsTransport, kind); + } + + transceiver.localCapabilities = localCapabilities; + transceiver.sendEncodingParameters = sendEncodingParameters; + }); + + // always offer BUNDLE and dispose on return if not supported. + if (pc._config.bundlePolicy !== 'max-compat') { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + sdp += writeMediaSection(transceiver, transceiver.localCapabilities, + 'offer', transceiver.stream, pc._dtlsRole); + sdp += 'a=rtcp-rsize\r\n'; + + if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && + (sdpMLineIndex === 0 || !pc.usingBundle)) { + transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { + cand.component = 1; + sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; + }); + + if (transceiver.iceGatherer.state === 'completed') { + sdp += 'a=end-of-candidates\r\n'; + } + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'offer', + sdp: sdp + }); + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.createAnswer = function() { + var pc = this; + + if (pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createAnswer after close')); + } + + if (!(pc.signalingState === 'have-remote-offer' || + pc.signalingState === 'have-local-pranswer')) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createAnswer in signalingState ' + pc.signalingState)); + } + + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + if (pc.usingBundle) { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + var mediaSectionsInOffer = SDPUtils.getMediaSections( + pc._remoteDescription.sdp).length; + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + if (sdpMLineIndex + 1 > mediaSectionsInOffer) { + return; + } + if (transceiver.rejected) { + if (transceiver.kind === 'application') { + if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt + sdp += 'm=application 0 DTLS/SCTP 5000\r\n'; + } else { + sdp += 'm=application 0 ' + transceiver.protocol + + ' webrtc-datachannel\r\n'; + } + } else if (transceiver.kind === 'audio') { + sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + + 'a=rtpmap:0 PCMU/8000\r\n'; + } else if (transceiver.kind === 'video') { + sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + + 'a=rtpmap:120 VP8/90000\r\n'; + } + sdp += 'c=IN IP4 0.0.0.0\r\n' + + 'a=inactive\r\n' + + 'a=mid:' + transceiver.mid + '\r\n'; + return; + } + + // FIXME: look at direction. + if (transceiver.stream) { + var localTrack; + if (transceiver.kind === 'audio') { + localTrack = transceiver.stream.getAudioTracks()[0]; + } else if (transceiver.kind === 'video') { + localTrack = transceiver.stream.getVideoTracks()[0]; + } + if (localTrack) { + // add RTX + if (edgeVersion >= 15019 && transceiver.kind === 'video' && + !transceiver.sendEncodingParameters[0].rtx) { + transceiver.sendEncodingParameters[0].rtx = { + ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 + }; + } + } + } + + // Calculate intersection of capabilities. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + sdp += writeMediaSection(transceiver, commonCapabilities, + 'answer', transceiver.stream, pc._dtlsRole); + if (transceiver.rtcpParameters && + transceiver.rtcpParameters.reducedSize) { + sdp += 'a=rtcp-rsize\r\n'; + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'answer', + sdp: sdp + }); + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.addIceCandidate = function(candidate) { + var pc = this; + var sections; + if (candidate && !(candidate.sdpMLineIndex !== undefined || + candidate.sdpMid)) { + return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required')); + } + + // TODO: needs to go into ops queue. + return new Promise(function(resolve, reject) { + if (!pc._remoteDescription) { + return reject(makeError('InvalidStateError', + 'Can not add ICE candidate without a remote description')); + } else if (!candidate || candidate.candidate === '') { + for (var j = 0; j < pc.transceivers.length; j++) { + if (pc.transceivers[j].rejected) { + continue; + } + pc.transceivers[j].iceTransport.addRemoteCandidate({}); + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[j] += 'a=end-of-candidates\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + if (pc.usingBundle) { + break; + } + } + } else { + var sdpMLineIndex = candidate.sdpMLineIndex; + if (candidate.sdpMid) { + for (var i = 0; i < pc.transceivers.length; i++) { + if (pc.transceivers[i].mid === candidate.sdpMid) { + sdpMLineIndex = i; + break; + } + } + } + var transceiver = pc.transceivers[sdpMLineIndex]; + if (transceiver) { + if (transceiver.rejected) { + return resolve(); + } + var cand = Object.keys(candidate.candidate).length > 0 ? + SDPUtils.parseCandidate(candidate.candidate) : {}; + // Ignore Chrome's invalid candidates since Edge does not like them. + if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { + return resolve(); + } + // Ignore RTCP candidates, we assume RTCP-MUX. + if (cand.component && cand.component !== 1) { + return resolve(); + } + // when using bundle, avoid adding candidates to the wrong + // ice transport. And avoid adding candidates added in the SDP. + if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && + transceiver.iceTransport !== pc.transceivers[0].iceTransport)) { + if (!maybeAddCandidate(transceiver.iceTransport, cand)) { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); + } + } + + // update the remoteDescription. + var candidateString = candidate.candidate.trim(); + if (candidateString.indexOf('a=') === 0) { + candidateString = candidateString.substr(2); + } + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[sdpMLineIndex] += 'a=' + + (cand.type ? candidateString : 'end-of-candidates') + + '\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + } else { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); + } + } + resolve(); + }); + }; + + RTCPeerConnection.prototype.getStats = function(selector) { + if (selector && selector instanceof window.MediaStreamTrack) { + var senderOrReceiver = null; + this.transceivers.forEach(function(transceiver) { + if (transceiver.rtpSender && + transceiver.rtpSender.track === selector) { + senderOrReceiver = transceiver.rtpSender; + } else if (transceiver.rtpReceiver && + transceiver.rtpReceiver.track === selector) { + senderOrReceiver = transceiver.rtpReceiver; + } + }); + if (!senderOrReceiver) { + throw makeError('InvalidAccessError', 'Invalid selector.'); + } + return senderOrReceiver.getStats(); + } + + var promises = []; + this.transceivers.forEach(function(transceiver) { + ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', + 'dtlsTransport'].forEach(function(method) { + if (transceiver[method]) { + promises.push(transceiver[method].getStats()); + } + }); + }); + return Promise.all(promises).then(function(allStats) { + var results = new Map(); + allStats.forEach(function(stats) { + stats.forEach(function(stat) { + results.set(stat.id, stat); + }); + }); + return results; + }); + }; + + // fix low-level stat names and return Map instead of object. + var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', + 'RTCIceTransport', 'RTCDtlsTransport']; + ortcObjects.forEach(function(ortcObjectName) { + var obj = window[ortcObjectName]; + if (obj && obj.prototype && obj.prototype.getStats) { + var nativeGetstats = obj.prototype.getStats; + obj.prototype.getStats = function() { + return nativeGetstats.apply(this) + .then(function(nativeStats) { + var mapStats = new Map(); + Object.keys(nativeStats).forEach(function(id) { + nativeStats[id].type = fixStatsType(nativeStats[id]); + mapStats.set(id, nativeStats[id]); + }); + return mapStats; + }); + }; + } + }); + + // legacy callback shims. Should be moved to adapter.js some days. + var methods = ['createOffer', 'createAnswer']; + methods.forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[0] === 'function' || + typeof args[1] === 'function') { // legacy + return nativeMethod.apply(this, [arguments[2]]) + .then(function(description) { + if (typeof args[0] === 'function') { + args[0].apply(null, [description]); + } + }, function(error) { + if (typeof args[1] === 'function') { + args[1].apply(null, [error]); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; + methods.forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[1] === 'function' || + typeof args[2] === 'function') { // legacy + return nativeMethod.apply(this, arguments) + .then(function() { + if (typeof args[1] === 'function') { + args[1].apply(null); + } + }, function(error) { + if (typeof args[2] === 'function') { + args[2].apply(null, [error]); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + // getStats is special. It doesn't have a spec legacy method yet we support + // getStats(something, cb) without error callbacks. + ['getStats'].forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[1] === 'function') { + return nativeMethod.apply(this, arguments) + .then(function() { + if (typeof args[1] === 'function') { + args[1].apply(null); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + return RTCPeerConnection; +}; + +},{"sdp":17}],17:[function(require,module,exports){ +/* eslint-env node */ +'use strict'; + +// SDP helpers. +var SDPUtils = {}; + +// Generate an alphanumeric identifier for cname or mids. +// TODO: use UUIDs instead? https://gist.github.com/jed/982883 +SDPUtils.generateIdentifier = function() { + return Math.random().toString(36).substr(2, 10); +}; + +// The RTCP CNAME used by all peerconnections from the same JS. +SDPUtils.localCName = SDPUtils.generateIdentifier(); + +// Splits SDP into lines, dealing with both CRLF and LF. +SDPUtils.splitLines = function(blob) { + return blob.trim().split('\n').map(function(line) { + return line.trim(); + }); +}; +// Splits SDP into sessionpart and mediasections. Ensures CRLF. +SDPUtils.splitSections = function(blob) { + var parts = blob.split('\nm='); + return parts.map(function(part, index) { + return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; + }); +}; + +// returns the session description. +SDPUtils.getDescription = function(blob) { + var sections = SDPUtils.splitSections(blob); + return sections && sections[0]; +}; + +// returns the individual media sections. +SDPUtils.getMediaSections = function(blob) { + var sections = SDPUtils.splitSections(blob); + sections.shift(); + return sections; +}; + +// Returns lines that start with a certain prefix. +SDPUtils.matchPrefix = function(blob, prefix) { + return SDPUtils.splitLines(blob).filter(function(line) { + return line.indexOf(prefix) === 0; + }); +}; + +// Parses an ICE candidate line. Sample input: +// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 +// rport 55996" +SDPUtils.parseCandidate = function(line) { + var parts; + // Parse both variants. + if (line.indexOf('a=candidate:') === 0) { + parts = line.substring(12).split(' '); + } else { + parts = line.substring(10).split(' '); + } + + var candidate = { + foundation: parts[0], + component: parseInt(parts[1], 10), + protocol: parts[2].toLowerCase(), + priority: parseInt(parts[3], 10), + ip: parts[4], + address: parts[4], // address is an alias for ip. + port: parseInt(parts[5], 10), + // skip parts[6] == 'typ' + type: parts[7] + }; + + for (var i = 8; i < parts.length; i += 2) { + switch (parts[i]) { + case 'raddr': + candidate.relatedAddress = parts[i + 1]; + break; + case 'rport': + candidate.relatedPort = parseInt(parts[i + 1], 10); + break; + case 'tcptype': + candidate.tcpType = parts[i + 1]; + break; + case 'ufrag': + candidate.ufrag = parts[i + 1]; // for backward compability. + candidate.usernameFragment = parts[i + 1]; + break; + default: // extension handling, in particular ufrag + candidate[parts[i]] = parts[i + 1]; + break; + } + } + return candidate; +}; + +// Translates a candidate object into SDP candidate attribute. +SDPUtils.writeCandidate = function(candidate) { + var sdp = []; + sdp.push(candidate.foundation); + sdp.push(candidate.component); + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.address || candidate.ip); + sdp.push(candidate.port); + + var type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type !== 'host' && candidate.relatedAddress && + candidate.relatedPort) { + sdp.push('raddr'); + sdp.push(candidate.relatedAddress); + sdp.push('rport'); + sdp.push(candidate.relatedPort); + } + if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } + if (candidate.usernameFragment || candidate.ufrag) { + sdp.push('ufrag'); + sdp.push(candidate.usernameFragment || candidate.ufrag); + } + return 'candidate:' + sdp.join(' '); +}; + +// Parses an ice-options line, returns an array of option tags. +// a=ice-options:foo bar +SDPUtils.parseIceOptions = function(line) { + return line.substr(14).split(' '); +}; + +// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: +// a=rtpmap:111 opus/48000/2 +SDPUtils.parseRtpMap = function(line) { + var parts = line.substr(9).split(' '); + var parsed = { + payloadType: parseInt(parts.shift(), 10) // was: id + }; + + parts = parts[0].split('/'); + + parsed.name = parts[0]; + parsed.clockRate = parseInt(parts[1], 10); // was: clockrate + parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; + // legacy alias, got renamed back to channels in ORTC. + parsed.numChannels = parsed.channels; + return parsed; +}; + +// Generate an a=rtpmap line from RTCRtpCodecCapability or +// RTCRtpCodecParameters. +SDPUtils.writeRtpMap = function(codec) { + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + var channels = codec.channels || codec.numChannels || 1; + return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + + (channels !== 1 ? '/' + channels : '') + '\r\n'; +}; + +// Parses an a=extmap line (headerextension from RFC 5285). Sample input: +// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset +// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset +SDPUtils.parseExtmap = function(line) { + var parts = line.substr(9).split(' '); + return { + id: parseInt(parts[0], 10), + direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', + uri: parts[1] + }; +}; + +// Generates a=extmap line from RTCRtpHeaderExtensionParameters or +// RTCRtpHeaderExtension. +SDPUtils.writeExtmap = function(headerExtension) { + return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + + (headerExtension.direction && headerExtension.direction !== 'sendrecv' + ? '/' + headerExtension.direction + : '') + + ' ' + headerExtension.uri + '\r\n'; +}; + +// Parses an ftmp line, returns dictionary. Sample input: +// a=fmtp:96 vbr=on;cng=on +// Also deals with vbr=on; cng=on +SDPUtils.parseFmtp = function(line) { + var parsed = {}; + var kv; + var parts = line.substr(line.indexOf(' ') + 1).split(';'); + for (var j = 0; j < parts.length; j++) { + kv = parts[j].trim().split('='); + parsed[kv[0].trim()] = kv[1]; + } + return parsed; +}; + +// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. +SDPUtils.writeFmtp = function(codec) { + var line = ''; + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.parameters && Object.keys(codec.parameters).length) { + var params = []; + Object.keys(codec.parameters).forEach(function(param) { + if (codec.parameters[param]) { + params.push(param + '=' + codec.parameters[param]); + } else { + params.push(param); + } + }); + line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; + } + return line; +}; + +// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: +// a=rtcp-fb:98 nack rpsi +SDPUtils.parseRtcpFb = function(line) { + var parts = line.substr(line.indexOf(' ') + 1).split(' '); + return { + type: parts.shift(), + parameter: parts.join(' ') + }; +}; +// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. +SDPUtils.writeRtcpFb = function(codec) { + var lines = ''; + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.rtcpFeedback && codec.rtcpFeedback.length) { + // FIXME: special handling for trr-int? + codec.rtcpFeedback.forEach(function(fb) { + lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + + '\r\n'; + }); + } + return lines; +}; + +// Parses an RFC 5576 ssrc media attribute. Sample input: +// a=ssrc:3735928559 cname:something +SDPUtils.parseSsrcMedia = function(line) { + var sp = line.indexOf(' '); + var parts = { + ssrc: parseInt(line.substr(7, sp - 7), 10) + }; + var colon = line.indexOf(':', sp); + if (colon > -1) { + parts.attribute = line.substr(sp + 1, colon - sp - 1); + parts.value = line.substr(colon + 1); + } else { + parts.attribute = line.substr(sp + 1); + } + return parts; +}; + +SDPUtils.parseSsrcGroup = function(line) { + var parts = line.substr(13).split(' '); + return { + semantics: parts.shift(), + ssrcs: parts.map(function(ssrc) { + return parseInt(ssrc, 10); + }) + }; +}; + +// Extracts the MID (RFC 5888) from a media section. +// returns the MID or undefined if no mid line was found. +SDPUtils.getMid = function(mediaSection) { + var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; + if (mid) { + return mid.substr(6); + } +}; + +SDPUtils.parseFingerprint = function(line) { + var parts = line.substr(14).split(' '); + return { + algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. + value: parts[1] + }; +}; + +// Extracts DTLS parameters from SDP media section or sessionpart. +// FIXME: for consistency with other functions this should only +// get the fingerprint line as input. See also getIceParameters. +SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=fingerprint:'); + // Note: a=setup line is ignored since we use the 'auto' role. + // Note2: 'algorithm' is not case sensitive except in Edge. + return { + role: 'auto', + fingerprints: lines.map(SDPUtils.parseFingerprint) + }; +}; + +// Serializes DTLS parameters to SDP. +SDPUtils.writeDtlsParameters = function(params, setupType) { + var sdp = 'a=setup:' + setupType + '\r\n'; + params.fingerprints.forEach(function(fp) { + sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; + }); + return sdp; +}; + +// Parses a=crypto lines into +// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members +SDPUtils.parseCryptoLine = function(line) { + var parts = line.substr(9).split(' '); + return { + tag: parseInt(parts[0], 10), + cryptoSuite: parts[1], + keyParams: parts[2], + sessionParams: parts.slice(3), + }; +}; + +SDPUtils.writeCryptoLine = function(parameters) { + return 'a=crypto:' + parameters.tag + ' ' + + parameters.cryptoSuite + ' ' + + (typeof parameters.keyParams === 'object' + ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) + : parameters.keyParams) + + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + + '\r\n'; +}; + +// Parses the crypto key parameters into +// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* +SDPUtils.parseCryptoKeyParams = function(keyParams) { + if (keyParams.indexOf('inline:') !== 0) { + return null; + } + var parts = keyParams.substr(7).split('|'); + return { + keyMethod: 'inline', + keySalt: parts[0], + lifeTime: parts[1], + mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, + mkiLength: parts[2] ? parts[2].split(':')[1] : undefined, + }; +}; + +SDPUtils.writeCryptoKeyParams = function(keyParams) { + return keyParams.keyMethod + ':' + + keyParams.keySalt + + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + + (keyParams.mkiValue && keyParams.mkiLength + ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength + : ''); +}; + +// Extracts all SDES paramters. +SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) { + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=crypto:'); + return lines.map(SDPUtils.parseCryptoLine); +}; + +// Parses ICE information from SDP media section or sessionpart. +// FIXME: for consistency with other functions this should only +// get the ice-ufrag and ice-pwd lines as input. +SDPUtils.getIceParameters = function(mediaSection, sessionpart) { + var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=ice-ufrag:')[0]; + var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=ice-pwd:')[0]; + if (!(ufrag && pwd)) { + return null; + } + return { + usernameFragment: ufrag.substr(12), + password: pwd.substr(10), + }; +}; + +// Serializes ICE parameters to SDP. +SDPUtils.writeIceParameters = function(params) { + return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + + 'a=ice-pwd:' + params.password + '\r\n'; +}; + +// Parses the SDP media section and returns RTCRtpParameters. +SDPUtils.parseRtpParameters = function(mediaSection) { + var description = { + codecs: [], + headerExtensions: [], + fecMechanisms: [], + rtcp: [] + }; + var lines = SDPUtils.splitLines(mediaSection); + var mline = lines[0].split(' '); + for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] + var pt = mline[i]; + var rtpmapline = SDPUtils.matchPrefix( + mediaSection, 'a=rtpmap:' + pt + ' ')[0]; + if (rtpmapline) { + var codec = SDPUtils.parseRtpMap(rtpmapline); + var fmtps = SDPUtils.matchPrefix( + mediaSection, 'a=fmtp:' + pt + ' '); + // Only the first a=fmtp:<pt> is considered. + codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; + codec.rtcpFeedback = SDPUtils.matchPrefix( + mediaSection, 'a=rtcp-fb:' + pt + ' ') + .map(SDPUtils.parseRtcpFb); + description.codecs.push(codec); + // parse FEC mechanisms from rtpmap lines. + switch (codec.name.toUpperCase()) { + case 'RED': + case 'ULPFEC': + description.fecMechanisms.push(codec.name.toUpperCase()); + break; + default: // only RED and ULPFEC are recognized as FEC mechanisms. + break; + } + } + } + SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { + description.headerExtensions.push(SDPUtils.parseExtmap(line)); + }); + // FIXME: parse rtcp. + return description; +}; + +// Generates parts of the SDP media section describing the capabilities / +// parameters. +SDPUtils.writeRtpDescription = function(kind, caps) { + var sdp = ''; + + // Build the mline. + sdp += 'm=' + kind + ' '; + sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. + sdp += ' UDP/TLS/RTP/SAVPF '; + sdp += caps.codecs.map(function(codec) { + if (codec.preferredPayloadType !== undefined) { + return codec.preferredPayloadType; + } + return codec.payloadType; + }).join(' ') + '\r\n'; + + sdp += 'c=IN IP4 0.0.0.0\r\n'; + sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; + + // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. + caps.codecs.forEach(function(codec) { + sdp += SDPUtils.writeRtpMap(codec); + sdp += SDPUtils.writeFmtp(codec); + sdp += SDPUtils.writeRtcpFb(codec); + }); + var maxptime = 0; + caps.codecs.forEach(function(codec) { + if (codec.maxptime > maxptime) { + maxptime = codec.maxptime; + } + }); + if (maxptime > 0) { + sdp += 'a=maxptime:' + maxptime + '\r\n'; + } + sdp += 'a=rtcp-mux\r\n'; + + if (caps.headerExtensions) { + caps.headerExtensions.forEach(function(extension) { + sdp += SDPUtils.writeExtmap(extension); + }); + } + // FIXME: write fecMechanisms. + return sdp; +}; + +// Parses the SDP media section and returns an array of +// RTCRtpEncodingParameters. +SDPUtils.parseRtpEncodingParameters = function(mediaSection) { + var encodingParameters = []; + var description = SDPUtils.parseRtpParameters(mediaSection); + var hasRed = description.fecMechanisms.indexOf('RED') !== -1; + var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; + + // filter a=ssrc:... cname:, ignore PlanB-msid + var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(parts) { + return parts.attribute === 'cname'; + }); + var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; + var secondarySsrc; + + var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') + .map(function(line) { + var parts = line.substr(17).split(' '); + return parts.map(function(part) { + return parseInt(part, 10); + }); + }); + if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { + secondarySsrc = flows[0][1]; + } + + description.codecs.forEach(function(codec) { + if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { + var encParam = { + ssrc: primarySsrc, + codecPayloadType: parseInt(codec.parameters.apt, 10) + }; + if (primarySsrc && secondarySsrc) { + encParam.rtx = {ssrc: secondarySsrc}; + } + encodingParameters.push(encParam); + if (hasRed) { + encParam = JSON.parse(JSON.stringify(encParam)); + encParam.fec = { + ssrc: primarySsrc, + mechanism: hasUlpfec ? 'red+ulpfec' : 'red' + }; + encodingParameters.push(encParam); + } + } + }); + if (encodingParameters.length === 0 && primarySsrc) { + encodingParameters.push({ + ssrc: primarySsrc + }); + } + + // we support both b=AS and b=TIAS but interpret AS as TIAS. + var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); + if (bandwidth.length) { + if (bandwidth[0].indexOf('b=TIAS:') === 0) { + bandwidth = parseInt(bandwidth[0].substr(7), 10); + } else if (bandwidth[0].indexOf('b=AS:') === 0) { + // use formula from JSEP to convert b=AS to TIAS value. + bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 + - (50 * 40 * 8); + } else { + bandwidth = undefined; + } + encodingParameters.forEach(function(params) { + params.maxBitrate = bandwidth; + }); + } + return encodingParameters; +}; + +// parses http://draft.ortc.org/#rtcrtcpparameters* +SDPUtils.parseRtcpParameters = function(mediaSection) { + var rtcpParameters = {}; + + // Gets the first SSRC. Note tha with RTX there might be multiple + // SSRCs. + var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(obj) { + return obj.attribute === 'cname'; + })[0]; + if (remoteSsrc) { + rtcpParameters.cname = remoteSsrc.value; + rtcpParameters.ssrc = remoteSsrc.ssrc; + } + + // Edge uses the compound attribute instead of reducedSize + // compound is !reducedSize + var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); + rtcpParameters.reducedSize = rsize.length > 0; + rtcpParameters.compound = rsize.length === 0; + + // parses the rtcp-mux attrіbute. + // Note that Edge does not support unmuxed RTCP. + var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); + rtcpParameters.mux = mux.length > 0; + + return rtcpParameters; +}; + +// parses either a=msid: or a=ssrc:... msid lines and returns +// the id of the MediaStream and MediaStreamTrack. +SDPUtils.parseMsid = function(mediaSection) { + var parts; + var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); + if (spec.length === 1) { + parts = spec[0].substr(7).split(' '); + return {stream: parts[0], track: parts[1]}; + } + var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(msidParts) { + return msidParts.attribute === 'msid'; + }); + if (planB.length > 0) { + parts = planB[0].value.split(' '); + return {stream: parts[0], track: parts[1]}; + } +}; + +// SCTP +// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back +// to draft-ietf-mmusic-sctp-sdp-05 +SDPUtils.parseSctpDescription = function(mediaSection) { + var mline = SDPUtils.parseMLine(mediaSection); + var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); + var maxMessageSize; + if (maxSizeLine.length > 0) { + maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10); + } + if (isNaN(maxMessageSize)) { + maxMessageSize = 65536; + } + var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); + if (sctpPort.length > 0) { + return { + port: parseInt(sctpPort[0].substr(12), 10), + protocol: mline.fmt, + maxMessageSize: maxMessageSize + }; + } + var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); + if (sctpMapLines.length > 0) { + var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0] + .substr(10) + .split(' '); + return { + port: parseInt(parts[0], 10), + protocol: parts[1], + maxMessageSize: maxMessageSize + }; + } +}; + +// SCTP +// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers +// support by now receiving in this format, unless we originally parsed +// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line +// protocol of DTLS/SCTP -- without UDP/ or TCP/) +SDPUtils.writeSctpDescription = function(media, sctp) { + var output = []; + if (media.protocol !== 'DTLS/SCTP') { + output = [ + 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', + 'c=IN IP4 0.0.0.0\r\n', + 'a=sctp-port:' + sctp.port + '\r\n' + ]; + } else { + output = [ + 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', + 'c=IN IP4 0.0.0.0\r\n', + 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n' + ]; + } + if (sctp.maxMessageSize !== undefined) { + output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); + } + return output.join(''); +}; + +// Generate a session ID for SDP. +// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 +// recommends using a cryptographically random +ve 64-bit value +// but right now this should be acceptable and within the right range +SDPUtils.generateSessionId = function() { + return Math.random().toString().substr(2, 21); +}; + +// Write boilder plate for start of SDP +// sessId argument is optional - if not supplied it will +// be generated randomly +// sessVersion is optional and defaults to 2 +// sessUser is optional and defaults to 'thisisadapterortc' +SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) { + var sessionId; + var version = sessVer !== undefined ? sessVer : 2; + if (sessId) { + sessionId = sessId; + } else { + sessionId = SDPUtils.generateSessionId(); + } + var user = sessUser || 'thisisadapterortc'; + // FIXME: sess-id should be an NTP timestamp. + return 'v=0\r\n' + + 'o=' + user + ' ' + sessionId + ' ' + version + + ' IN IP4 127.0.0.1\r\n' + + 's=-\r\n' + + 't=0 0\r\n'; +}; + +SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { + var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); + + // Map ICE parameters (ufrag, pwd) to SDP. + sdp += SDPUtils.writeIceParameters( + transceiver.iceGatherer.getLocalParameters()); + + // Map DTLS parameters to SDP. + sdp += SDPUtils.writeDtlsParameters( + transceiver.dtlsTransport.getLocalParameters(), + type === 'offer' ? 'actpass' : 'active'); + + sdp += 'a=mid:' + transceiver.mid + '\r\n'; + + if (transceiver.direction) { + sdp += 'a=' + transceiver.direction + '\r\n'; + } else if (transceiver.rtpSender && transceiver.rtpReceiver) { + sdp += 'a=sendrecv\r\n'; + } else if (transceiver.rtpSender) { + sdp += 'a=sendonly\r\n'; + } else if (transceiver.rtpReceiver) { + sdp += 'a=recvonly\r\n'; + } else { + sdp += 'a=inactive\r\n'; + } + + if (transceiver.rtpSender) { + // spec. + var msid = 'msid:' + stream.id + ' ' + + transceiver.rtpSender.track.id + '\r\n'; + sdp += 'a=' + msid; + + // for Chrome. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' ' + msid; + if (transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' ' + msid; + sdp += 'a=ssrc-group:FID ' + + transceiver.sendEncodingParameters[0].ssrc + ' ' + + transceiver.sendEncodingParameters[0].rtx.ssrc + + '\r\n'; + } + } + // FIXME: this should be written by writeRtpDescription. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + } + return sdp; +}; + +// Gets the direction from the mediaSection or the sessionpart. +SDPUtils.getDirection = function(mediaSection, sessionpart) { + // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. + var lines = SDPUtils.splitLines(mediaSection); + for (var i = 0; i < lines.length; i++) { + switch (lines[i]) { + case 'a=sendrecv': + case 'a=sendonly': + case 'a=recvonly': + case 'a=inactive': + return lines[i].substr(2); + default: + // FIXME: What should happen here? + } + } + if (sessionpart) { + return SDPUtils.getDirection(sessionpart); + } + return 'sendrecv'; +}; + +SDPUtils.getKind = function(mediaSection) { + var lines = SDPUtils.splitLines(mediaSection); + var mline = lines[0].split(' '); + return mline[0].substr(2); +}; + +SDPUtils.isRejected = function(mediaSection) { + return mediaSection.split(' ', 2)[1] === '0'; +}; + +SDPUtils.parseMLine = function(mediaSection) { + var lines = SDPUtils.splitLines(mediaSection); + var parts = lines[0].substr(2).split(' '); + return { + kind: parts[0], + port: parseInt(parts[1], 10), + protocol: parts[2], + fmt: parts.slice(3).join(' ') + }; +}; + +SDPUtils.parseOLine = function(mediaSection) { + var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; + var parts = line.substr(2).split(' '); + return { + username: parts[0], + sessionId: parts[1], + sessionVersion: parseInt(parts[2], 10), + netType: parts[3], + addressType: parts[4], + address: parts[5] + }; +}; + +// a very naive interpretation of a valid SDP. +SDPUtils.isValidSDP = function(blob) { + if (typeof blob !== 'string' || blob.length === 0) { + return false; + } + var lines = SDPUtils.splitLines(blob); + for (var i = 0; i < lines.length; i++) { + if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { + return false; + } + // TODO: check the modifier a bit more. + } + return true; +}; + +// Expose public methods. +if (typeof module === 'object') { + module.exports = SDPUtils; +} + +},{}]},{},[1])(1) +});
diff --git a/tools/perf/page_sets/webrtc_cases/adapter.js b/tools/perf/page_sets/webrtc_cases/adapter.js deleted file mode 100644 index a3c0b08..0000000 --- a/tools/perf/page_sets/webrtc_cases/adapter.js +++ /dev/null
@@ -1,3976 +0,0 @@ -/* - * Copyright 2017 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr - sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp:<pt> is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.split(' '); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } - }; - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -// Expose public methods. -module.exports = SDPUtils; - -},{}],2:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":3}],3:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var utils = require('./utils'); - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - utils.shimCreateObjectURL(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - - firefoxShim.shimGetUserMedia(window); - utils.shimCreateObjectURL(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - - edgeShim.shimGetUserMedia(window); - utils.shimCreateObjectURL(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - // shim window.URL.createObjectURL Safari (technical preview) - utils.shimCreateObjectURL(window); - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimGetUserMedia(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":4,"./edge/edge_shim":6,"./firefox/firefox_shim":9,"./safari/safari_shim":11,"./utils":12}],4:[function(require,module,exports){ - -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -var chromeShim = { - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - } - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrack: function(window) { - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack) { - return; - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var self = this; - var nativeStreams = origGetLocalStreams.apply(this); - self._reverseStreams = self._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return self._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - pc.dispatchEvent(new Event('negotiationneeded')); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(stream); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - console.warn('RTCIceServer.url is deprecated! Use urls instead.'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var self = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(self, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var self = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(self, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var self = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof arguments[0] === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(self, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - - -// Expose public methods. -module.exports = { - shimMediaStream: chromeShim.shimMediaStream, - shimOnTrack: chromeShim.shimOnTrack, - shimAddTrackRemoveTrack: chromeShim.shimAddTrackRemoveTrack, - shimGetSendersWithDtmf: chromeShim.shimGetSendersWithDtmf, - shimSourceObject: chromeShim.shimSourceObject, - shimPeerConnection: chromeShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; - -},{"../utils.js":12,"./getusermedia":5}],5:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - var constraintsToChrome_ = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function(constraints, func) { - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 61; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - InvalidStateError: 'NotReadableError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotReadableError', - MediaDeviceKillSwitchOn: 'NotReadableError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - onError(shimError_(e)); - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return getUserMediaPromise_(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":12}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var shimRTCPeerConnection = require('./rtcpeerconnection_shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - - window.RTCPeerConnection = - shimRTCPeerConnection(window, browserDetails.version); - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":12,"./getusermedia":7,"./rtcpeerconnection_shim":8}],7:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],8:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); - -// sort tracks such that they follow an a-v-a-v... -// pattern. -function sortTracks(tracks) { - var audioTracks = tracks.filter(function(track) { - return track.kind === 'audio'; - }); - var videoTracks = tracks.filter(function(track) { - return track.kind === 'video'; - }); - tracks = []; - while (audioTracks.length || videoTracks.length) { - if (audioTracks.length) { - tracks.push(audioTracks.shift()); - } - if (videoTracks.length) { - tracks.push(videoTracks.shift()); - } - } - return tracks; -} - -// Edge does not like -// 1) stun: -// 2) turn: that does not have all of turn:host:port?transport=udp -// 3) turn: with ipv6 addresses -// 4) turn: occurring muliple times -function filterIceServers(iceServers, edgeVersion) { - var hasTurn = false; - iceServers = JSON.parse(JSON.stringify(iceServers)); - return iceServers.filter(function(server) { - if (server && (server.urls || server.url)) { - var urls = server.urls || server.url; - if (server.url && !server.urls) { - console.warn('RTCIceServer.url is deprecated! Use urls instead.'); - } - var isString = typeof urls === 'string'; - if (isString) { - urls = [urls]; - } - urls = urls.filter(function(url) { - var validTurn = url.indexOf('turn:') === 0 && - url.indexOf('transport=udp') !== -1 && - url.indexOf('turn:[') === -1 && - !hasTurn; - - if (validTurn) { - hasTurn = true; - return true; - } - return url.indexOf('stun:') === 0 && edgeVersion >= 14393; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - return false; - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -module.exports = function(window, edgeVersion) { - var RTCPeerConnection = function(config) { - var self = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - self[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.needNegotiation = false; - - this.onicecandidate = null; - this.onaddstream = null; - this.ontrack = null; - this.onremovestream = null; - this.onsignalingstatechange = null; - this.oniceconnectionstatechange = null; - this.onicegatheringstatechange = null; - this.onnegotiationneeded = null; - this.ondatachannel = null; - this.canTrickleIceCandidates = null; - - this.localStreams = []; - this.remoteStreams = []; - this.getLocalStreams = function() { - return self.localStreams; - }; - this.getRemoteStreams = function() { - return self.remoteStreams; - }; - - this.localDescription = new window.RTCSessionDescription({ - type: '', - sdp: '' - }); - this.remoteDescription = new window.RTCSessionDescription({ - type: '', - sdp: '' - }); - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - this.iceOptions = { - gatherPolicy: 'all', - iceServers: [] - }; - if (config && config.iceTransportPolicy) { - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - this.iceOptions.gatherPolicy = config.iceTransportPolicy; - break; - default: - // don't set iceTransportPolicy. - break; - } - } - this.usingBundle = config && config.bundlePolicy === 'max-bundle'; - - if (config && config.iceServers) { - this.iceOptions.iceServers = filterIceServers(config.iceServers, - edgeVersion); - } - this._config = config || {}; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - // since the iceGatherer is currently created in createOffer but we - // must not emit candidates until after setLocalDescription we buffer - // them in this array. - this._localIceCandidatesBuffer = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this.dispatchEvent(event); - if (this.onicegatheringstatechange !== null) { - this.onicegatheringstatechange(event); - } - }; - - RTCPeerConnection.prototype._emitBufferedCandidates = function() { - var self = this; - var sections = SDPUtils.splitSections(self.localDescription.sdp); - // FIXME: need to apply ice candidates in a way which is async but - // in-order - this._localIceCandidatesBuffer.forEach(function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - if (end) { - for (var j = 1; j < sections.length; j++) { - if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) { - sections[j] += 'a=end-of-candidates\r\n'; - } - } - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } - self.localDescription.sdp = sections.join(''); - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - if (!event.candidate && self.iceGatheringState !== 'complete') { - var complete = self.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - if (complete && self.iceGatheringStateChange !== 'complete') { - self.iceGatheringState = 'complete'; - self._emitGatheringStateChange(); - } - } - }); - this._localIceCandidatesBuffer = []; - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - this.transceivers.push(transceiver); - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - - this._maybeFireNegotiationNeeded(); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var self = this; - if (edgeVersion >= 15025) { - this.localStreams.push(stream); - stream.getTracks().forEach(function(track) { - self.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - self.addTrack(track, clonedStream); - }); - this.localStreams.push(clonedStream); - } - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var idx = this.localStreams.indexOf(stream); - if (idx > -1) { - this.localStreams.splice(idx, 1); - this._maybeFireNegotiationNeeded(); - } - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - // Create ICE gatherer and hook it up. - RTCPeerConnection.prototype._createIceGatherer = function(mid, - sdpMLineIndex) { - var self = this; - var iceGatherer = new window.RTCIceGatherer(self.iceOptions); - iceGatherer.onlocalcandidate = function(evt) { - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - var end = !cand || Object.keys(cand).length === 0; - // Edge emits an empty object for RTCIceCandidateComplete‥ - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === undefined) { - iceGatherer.state = 'completed'; - } - } else { - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(self.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - self.localDescription.sdp = sections.join(''); - var transceivers = self._pendingOffer ? self._pendingOffer : - self.transceivers; - var complete = transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - // Emit candidate if localDescription is set. - // Also emits null candidate when all gatherers are complete. - switch (self.iceGatheringState) { - case 'new': - if (!end) { - self._localIceCandidatesBuffer.push(event); - } - if (end && complete) { - self._localIceCandidatesBuffer.push( - new Event('icecandidate')); - } - break; - case 'gathering': - self._emitBufferedCandidates(); - if (!end) { - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - } - if (complete) { - self.dispatchEvent(new Event('icecandidate')); - if (self.onicecandidate !== null) { - self.onicecandidate(new Event('icecandidate')); - } - self.iceGatheringState = 'complete'; - self._emitGatheringStateChange(); - } - break; - case 'complete': - // should not happen... currently! - break; - default: // no-op. - break; - } - }; - return iceGatherer; - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var self = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - self._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - self._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - self._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - params.encodings = transceiver.recvEncodingParameters; - params.rtcp = { - cname: transceiver.rtcpParameters.cname, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var self = this; - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState)) { - var e = new Error('Can not set local ' + description.type + - ' in state ' + this.signalingState); - e.name = 'InvalidStateError'; - if (arguments.length > 2 && typeof arguments[2] === 'function') { - window.setTimeout(arguments[2], 0, e); - } - return Promise.reject(e); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // FIXME: What was the purpose of this empty if statement? - // if (!this._pendingOffer) { - // } else { - if (this._pendingOffer) { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - self._pendingOffer[sdpMLineIndex].localCapabilities = caps; - }); - this.transceivers = this._pendingOffer; - delete this._pendingOffer; - } - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(self.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = self.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - var rejected = SDPUtils.isRejected(mediaSection); - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - dtlsTransport.start(remoteDtlsParameters); - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - self._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - // If a success callback was provided, emit ICE candidates after it - // has been executed. Otherwise, emit callback after the Promise is - // resolved. - var hasCallback = arguments.length > 1 && - typeof arguments[1] === 'function'; - if (hasCallback) { - var cb = arguments[1]; - window.setTimeout(function() { - cb(); - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - self._emitBufferedCandidates(); - }, 0); - } - var p = Promise.resolve(); - p.then(function() { - if (!hasCallback) { - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - // Usually candidates will be emitted earlier. - window.setTimeout(self._emitBufferedCandidates.bind(self), 500); - } - }); - return p; - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var self = this; - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState)) { - var e = new Error('Can not set remote ' + description.type + - ' in state ' + this.signalingState); - e.name = 'InvalidStateError'; - if (arguments.length > 2 && typeof arguments[2] === 'function') { - window.setTimeout(arguments[2], 0, e); - } - return Promise.reject(e); - } - - var streams = {}; - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - this.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - var rejected = SDPUtils.isRejected(mediaSection); - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { - self.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === '1' || cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - self.transceivers[sdpMLineIndex]) { - self._disposeIceAndDtlsTransports(sdpMLineIndex); - self.transceivers[sdpMLineIndex].iceGatherer = - self.transceivers[0].iceGatherer; - self.transceivers[sdpMLineIndex].iceTransport = - self.transceivers[0].iceTransport; - self.transceivers[sdpMLineIndex].dtlsTransport = - self.transceivers[0].dtlsTransport; - if (self.transceivers[sdpMLineIndex].rtpSender) { - self.transceivers[sdpMLineIndex].rtpSender.setTransport( - self.transceivers[0].dtlsTransport); - } - if (self.transceivers[sdpMLineIndex].rtpReceiver) { - self.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - self.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex] || - self._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = usingBundle && sdpMLineIndex > 0 ? - self.transceivers[0].iceGatherer : - self._createIceGatherer(mid, sdpMLineIndex); - } - - if (isComplete && cands.length && - (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - if (direction === 'sendrecv' || direction === 'sendonly') { - rtpReceiver = new window.RTCRtpReceiver(transceiver.dtlsTransport, - kind); - - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - streams[remoteMsid.stream].addTrack(track); - receiverList.push([track, rtpReceiver, - streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - streams.default.addTrack(track); - receiverList.push([track, rtpReceiver, streams.default]); - } - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - self._transceive(self.transceivers[sdpMLineIndex], - false, - direction === 'sendrecv' || direction === 'sendonly'); - } else if (description.type === 'answer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - self.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - self.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - self.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (!usingBundle || sdpMLineIndex === 0) { - if ((isIceLite || isComplete) && cands.length) { - iceTransport.setRemoteCandidates(cands); - } - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - dtlsTransport.start(remoteDtlsParameters); - } - - self._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - streams[remoteMsid.stream].addTrack(track); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - streams.default.addTrack(track); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - self.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - self.dispatchEvent(event); - if (self.onaddstream !== null) { - window.setTimeout(function() { - self.onaddstream(event); - }, 0); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.streams = [stream]; - self.dispatchEvent(trackEvent); - if (self.ontrack !== null) { - window.setTimeout(function() { - self.ontrack(trackEvent); - }, 0); - } - }); - } - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(self && self.transceivers)) { - return; - } - self.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this.dispatchEvent(event); - if (this.onsignalingstatechange !== null) { - this.onsignalingstatechange(event); - } - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var self = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (self.needNegotiation === false) { - return; - } - self.needNegotiation = false; - var event = new Event('negotiationneeded'); - self.dispatchEvent(event); - if (self.onnegotiationneeded !== null) { - self.onnegotiationneeded(event); - } - }, 0); - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var self = this; - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== self.iceConnectionState) { - self.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this.dispatchEvent(event); - if (this.oniceconnectionstatechange !== null) { - this.oniceconnectionstatechange(event); - } - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var self = this; - if (this._pendingOffer) { - throw new Error('createOffer called while there is a pending offer.'); - } - var offerOptions; - if (arguments.length === 1 && typeof arguments[0] !== 'function') { - offerOptions = arguments[0]; - } else if (arguments.length === 3) { - offerOptions = arguments[2]; - } - - var numAudioTracks = this.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = this.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - this.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - this._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - this._createTransceiver('video'); - numVideoTracks--; - } - } - // reorder tracks - var transceivers = sortTracks(this.transceivers); - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); - transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = self.usingBundle && sdpMLineIndex > 0 ? - transceivers[0].iceGatherer : - self._createIceGatherer(mid, sdpMLineIndex); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video') { - sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 1) * 1001 + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, - kind - ); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += SDPUtils.writeMediaSection(transceiver, - transceiver.localCapabilities, 'offer', transceiver.stream); - sdp += 'a=rtcp-rsize\r\n'; - }); - - this._pendingOffer = transceivers; - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video') { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - if (!candidate) { - for (var j = 0; j < this.transceivers.length; j++) { - this.transceivers[j].iceTransport.addRemoteCandidate({}); - if (this.usingBundle) { - return Promise.resolve(); - } - } - } else { - var mLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - mLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[mLineIndex]; - if (transceiver) { - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && - !(cand.component === '1' || cand.component === 1)) { - return Promise.resolve(); - } - transceiver.iceTransport.addRemoteCandidate(cand); - - // update the remoteDescription. - var sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim() - : 'a=end-of-candidates') + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var cb = arguments.length > 1 && typeof arguments[1] === 'function' && - arguments[1]; - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - if (cb) { - window.setTimeout(cb, 0, results); - } - resolve(results); - }); - }); - }; - return RTCPeerConnection; -}; - -},{"sdp":1}],9:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -var firefoxShim = { - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - } -}; - -// Expose public methods. -module.exports = { - shimOnTrack: firefoxShim.shimOnTrack, - shimSourceObject: firefoxShim.shimSourceObject, - shimPeerConnection: firefoxShim.shimPeerConnection, - shimGetUserMedia: require('./getusermedia') -}; - -},{"../utils":12,"./getusermedia":10}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var getUserMedia_ = function(constraints, onSuccess, onError) { - var constraintsToFF37_ = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r. min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - console.warn('navigator.getUserMedia has been replaced by ' + - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":12}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; -var utils = require('../utils'); - -var safariShim = { - // TODO: DrAlex, should be here, double check against LayoutTests - - // TODO: once the back-end for the mac port is done, add. - // TODO: check for webkitGTK+ - // shimPeerConnection: function() { }, - - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var self = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(self, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var self = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - self.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - var stream = e.streams[0]; - if (!this._remoteStreams) { - this._remoteStreams = []; - } - if (this._remoteStreams.indexOf(stream) >= 0) { - return; - } - this._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = e.streams[0]; - this.dispatchEvent(event); - }.bind(this)); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } -}; - -// Expose public methods. -module.exports = { - shimCallbacksAPI: safariShim.shimCallbacksAPI, - shimLocalStreamsAPI: safariShim.shimLocalStreamsAPI, - shimRemoteStreamsAPI: safariShim.shimRemoteStreamsAPI, - shimGetUserMedia: safariShim.shimGetUserMedia, - shimRTCIceServerUrls: safariShim.shimRTCIceServerUrls - // TODO - // shimPeerConnection: safariShim.shimPeerConnection -}; - -},{"../utils":12}],12:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -// Utility methods. -var utils = { - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ - extractVersion: function(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - // Firefox. - if (navigator.mozGetUserMedia) { - result.browser = 'firefox'; - result.version = this.extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera, all use the chrome shim for now - if (window.webkitRTCPeerConnection) { - result.browser = 'chrome'; - result.version = this.extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else { // Safari (in an unpublished version) or unknown webkit-based. - if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) { - result.browser = 'safari'; - result.version = this.extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // unknown webkit-based browser. - result.browser = 'Unsupported webkit-based browser ' + - 'with GUM support but no WebRTC support.'; - return result; - } - } - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = this.extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { - // Safari, with webkitGetUserMedia removed. - result.browser = 'safari'; - result.version = this.extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - } -}; - -// Export. -module.exports = { - log: utils.log, - deprecated: utils.deprecated, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings, - extractVersion: utils.extractVersion, - shimCreateObjectURL: utils.shimCreateObjectURL, - detectBrowser: utils.detectBrowser.bind(utils) -}; - -},{}]},{},[2])(2) -}); \ No newline at end of file
diff --git a/tools/perf/page_sets/webrtc_cases/audio.html b/tools/perf/page_sets/webrtc_cases/audio.html deleted file mode 100644 index 035888d..0000000 --- a/tools/perf/page_sets/webrtc_cases/audio.html +++ /dev/null
@@ -1,63 +0,0 @@ -<!DOCTYPE html> -<!-- - * Copyright 2017 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. ---> -<html> -<head> - - - <base target="_blank"> - - <title>Peer connection: audio only</title> - - -</head> - -<body> - - <div id="container"> - - <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Peer connection: audio only</span></h1> - - <div id="audio"> - <div> - <div class="label">Local audio:</div><audio id="audio1" autoplay controls muted></audio> - </div> - <div> - <div class="label">Remote audio:</div><audio id="audio2" autoplay controls></audio> - </div> - </div> - - <div id="buttons"> - <select id="codec"> - <!-- Codec values are matched with how they appear in the SDP. - For instance, opus matches opus/48000/2 in Chrome, and ISAC/16000 - matches 16K iSAC (but not 32K iSAC). --> - <option value="opus">Opus</option> - <option value="ISAC">iSAC 16K</option> - <option value="G722">G722</option> - <option value="PCMU">PCMU</option> - </select> - <button id="callButton">Call</button> - <button id="hangupButton">Hang Up</button> - </div> - <div class="graph-container" id="bitrateGraph"> - <div>Bitrate</div> - <canvas id="bitrateCanvas"></canvas> - </div> - <div class="graph-container" id="packetGraph"> - <div>Packets sent per second</div> - <canvas id="packetCanvas"></canvas> - </div> - - <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/peerconnection/audio" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> - - </div> - - -<script src="audio.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> -</body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/audio.js b/tools/perf/page_sets/webrtc_cases/audio.js deleted file mode 100644 index 588f643..0000000 --- a/tools/perf/page_sets/webrtc_cases/audio.js +++ /dev/null
@@ -1,311 +0,0 @@ -/* - * Copyright 2017 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -'use strict'; - -var audio2 = document.querySelector('audio#audio2'); -var callButton = document.querySelector('button#callButton'); -var hangupButton = document.querySelector('button#hangupButton'); -var codecSelector = document.querySelector('select#codec'); -hangupButton.disabled = true; -callButton.onclick = call; -hangupButton.onclick = hangup; - -var pc1; -var pc2; -var localStream; - -var bitrateGraph; -var bitrateSeries; - -var packetGraph; -var packetSeries; - -var lastResult; - -var offerOptions = { - offerToReceiveAudio: 1, - offerToReceiveVideo: 0, - voiceActivityDetection: false -}; - -function gotStream(stream) { - hangupButton.disabled = false; - trace('Received local stream'); - localStream = stream; - var audioTracks = localStream.getAudioTracks(); - if (audioTracks.length > 0) { - trace('Using Audio device: ' + audioTracks[0].label); - } - localStream.getTracks().forEach( - function(track) { - pc1.addTrack( - track, - localStream - ); - } - ); - trace('Adding Local Stream to peer connection'); - - pc1.createOffer( - offerOptions - ).then( - gotDescription1, - onCreateSessionDescriptionError - ); - - bitrateSeries = new TimelineDataSeries(); - bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas'); - bitrateGraph.updateEndDate(); - - packetSeries = new TimelineDataSeries(); - packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas'); - packetGraph.updateEndDate(); -} - -function onCreateSessionDescriptionError(error) { - trace('Failed to create session description: ' + error.toString()); -} - -function call() { - callButton.disabled = true; - codecSelector.disabled = true; - trace('Starting call'); - var servers = null; - var pcConstraints = { - 'optional': [] - }; - pc1 = new RTCPeerConnection(servers, pcConstraints); - trace('Created local peer connection object pc1'); - pc1.onicecandidate = function(e) { - onIceCandidate(pc1, e); - }; - pc2 = new RTCPeerConnection(servers, pcConstraints); - trace('Created remote peer connection object pc2'); - pc2.onicecandidate = function(e) { - onIceCandidate(pc2, e); - }; - pc2.ontrack = gotRemoteStream; - trace('Requesting local stream'); - navigator.mediaDevices.getUserMedia({ - audio: true, - video: false - }) - .then(gotStream) - .catch(function(e) { - alert('getUserMedia() error: ' + e.name); - }); -} - -function gotDescription1(desc) { - trace('Offer from pc1 \n' + desc.sdp); - pc1.setLocalDescription(desc).then( - function() { - desc.sdp = forceChosenAudioCodec(desc.sdp); - pc2.setRemoteDescription(desc).then( - function() { - pc2.createAnswer().then( - gotDescription2, - onCreateSessionDescriptionError - ); - }, - onSetSessionDescriptionError - ); - }, - onSetSessionDescriptionError - ); -} - -function gotDescription2(desc) { - trace('Answer from pc2 \n' + desc.sdp); - pc2.setLocalDescription(desc).then( - function() { - desc.sdp = forceChosenAudioCodec(desc.sdp); - pc1.setRemoteDescription(desc).then( - function() { - }, - onSetSessionDescriptionError - ); - }, - onSetSessionDescriptionError - ); -} - -function hangup() { - trace('Ending call'); - localStream.getTracks().forEach(function(track) { - track.stop(); - }); - pc1.close(); - pc2.close(); - pc1 = null; - pc2 = null; - hangupButton.disabled = true; - callButton.disabled = false; - codecSelector.disabled = false; -} - -function gotRemoteStream(e) { - if (audio2.srcObject !== e.streams[0]) { - audio2.srcObject = e.streams[0]; - trace('Received remote stream'); - } -} - -function getOtherPc(pc) { - return (pc === pc1) ? pc2 : pc1; -} - -function getName(pc) { - return (pc === pc1) ? 'pc1' : 'pc2'; -} - -function onIceCandidate(pc, event) { - getOtherPc(pc).addIceCandidate(event.candidate) - .then( - function() { - onAddIceCandidateSuccess(pc); - }, - function(err) { - onAddIceCandidateError(pc, err); - } - ); - trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ? - event.candidate.candidate : '(null)')); -} - -function onAddIceCandidateSuccess() { - trace('AddIceCandidate success.'); -} - -function onAddIceCandidateError(error) { - trace('Failed to add ICE Candidate: ' + error.toString()); -} - -function onSetSessionDescriptionError(error) { - trace('Failed to set session description: ' + error.toString()); -} - -function forceChosenAudioCodec(sdp) { - return maybePreferCodec(sdp, 'audio', 'send', codecSelector.value); -} - -// Copied from AppRTC's sdputils.js: - -// Sets |codec| as the default |type| codec if it's present. -// The format of |codec| is 'NAME/RATE', e.g. 'opus/48000'. -function maybePreferCodec(sdp, type, dir, codec) { - var str = type + ' ' + dir + ' codec'; - if (codec === '') { - trace('No preference on ' + str + '.'); - return sdp; - } - - trace('Prefer ' + str + ': ' + codec); - - var sdpLines = sdp.split('\r\n'); - - // Search for m line. - var mLineIndex = findLine(sdpLines, 'm=', type); - if (mLineIndex === null) { - return sdp; - } - - // If the codec is available, set it as the default in m line. - var codecIndex = findLine(sdpLines, 'a=rtpmap', codec); - console.log('codecIndex', codecIndex); - if (codecIndex) { - var payload = getCodecPayloadType(sdpLines[codecIndex]); - if (payload) { - sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], payload); - } - } - - sdp = sdpLines.join('\r\n'); - return sdp; -} - -// Find the line in sdpLines that starts with |prefix|, and, if specified, -// contains |substr| (case-insensitive search). -function findLine(sdpLines, prefix, substr) { - return findLineInRange(sdpLines, 0, -1, prefix, substr); -} - -// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| -// and, if specified, contains |substr| (case-insensitive search). -function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { - var realEndLine = endLine !== -1 ? endLine : sdpLines.length; - for (var i = startLine; i < realEndLine; ++i) { - if (sdpLines[i].indexOf(prefix) === 0) { - if (!substr || - sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { - return i; - } - } - } - return null; -} - -// Gets the codec payload type from an a=rtpmap:X line. -function getCodecPayloadType(sdpLine) { - var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); - var result = sdpLine.match(pattern); - return (result && result.length === 2) ? result[1] : null; -} - -// Returns a new m= line with the specified codec as the first one. -function setDefaultCodec(mLine, payload) { - var elements = mLine.split(' '); - - // Just copy the first three parameters; codec order starts on fourth. - var newLine = elements.slice(0, 3); - - // Put target payload first and copy in the rest. - newLine.push(payload); - for (var i = 3; i < elements.length; i++) { - if (elements[i] !== payload) { - newLine.push(elements[i]); - } - } - return newLine.join(' '); -} - -// query getStats every second -window.setInterval(function() { - if (!window.pc1) { - return; - } - window.pc1.getStats(null).then(function(res) { - res.forEach(function(report) { - var bytes; - var packets; - var now = report.timestamp; - if ((report.type === 'outboundrtp') || - (report.type === 'outbound-rtp') || - (report.type === 'ssrc' && report.bytesSent)) { - bytes = report.bytesSent; - packets = report.packetsSent; - if (lastResult && lastResult.get(report.id)) { - // calculate bitrate - var bitrate = 8 * (bytes - lastResult.get(report.id).bytesSent) / - (now - lastResult.get(report.id).timestamp); - - // append to chart - bitrateSeries.addPoint(now, bitrate); - bitrateGraph.setDataSeries([bitrateSeries]); - bitrateGraph.updateEndDate(); - - // calculate number of packets and append to chart - packetSeries.addPoint(now, packets - - lastResult.get(report.id).packetsSent); - packetGraph.setDataSeries([packetSeries]); - packetGraph.updateEndDate(); - } - } - }); - lastResult = res; - }); -}, 1000);
diff --git a/tools/perf/page_sets/webrtc_cases/canvas-capture.html b/tools/perf/page_sets/webrtc_cases/canvas-capture.html index 018cb25..2fd7288 100644 --- a/tools/perf/page_sets/webrtc_cases/canvas-capture.html +++ b/tools/perf/page_sets/webrtc_cases/canvas-capture.html
@@ -21,6 +21,5 @@ <script src="canvas-capture.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/codec_constraints.html b/tools/perf/page_sets/webrtc_cases/codec_constraints.html index 1e85c49..d524a11 100644 --- a/tools/perf/page_sets/webrtc_cases/codec_constraints.html +++ b/tools/perf/page_sets/webrtc_cases/codec_constraints.html
@@ -51,6 +51,5 @@ <script src="codec_constraints.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/codec_constraints.js b/tools/perf/page_sets/webrtc_cases/codec_constraints.js index 1a1cf91..5909c64 100644 --- a/tools/perf/page_sets/webrtc_cases/codec_constraints.js +++ b/tools/perf/page_sets/webrtc_cases/codec_constraints.js
@@ -90,10 +90,7 @@ startButton.disabled = true; navigator.mediaDevices.getUserMedia({ audio: true, - video: { - width: {exact: 1280}, - height: {exact: 720}, - }, + video: true }) .then(gotStream) .catch(function(e) {
diff --git a/tools/perf/page_sets/webrtc_cases/common.js b/tools/perf/page_sets/webrtc_cases/common.js deleted file mode 100644 index 047a000..0000000 --- a/tools/perf/page_sets/webrtc_cases/common.js +++ /dev/null
@@ -1,12 +0,0 @@ -/* - * Copyright 2017 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - /* exported trace */ - -// Logging utility function. -function trace(arg) { - var now = (window.performance.now() / 1000).toFixed(3); - console.log(now + ': ', arg); -}
diff --git a/tools/perf/page_sets/webrtc_cases/datatransfer.html b/tools/perf/page_sets/webrtc_cases/datatransfer.html index 2c6315e..32e04d6 100644 --- a/tools/perf/page_sets/webrtc_cases/datatransfer.html +++ b/tools/perf/page_sets/webrtc_cases/datatransfer.html
@@ -8,66 +8,75 @@ <head> - <base target="_blank"> + <base target="_blank"> - <title>Generate and transfer data</title> + <title>Generate and transfer data</title> </head> <body> - <div id="container"> +<div id="container"> - <h1><a href="https://webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Generate and transfer data</span></h1> + <h1><a href="https://webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>Generate and transfer data</span> + </h1> <section> - <p>This page generates and sends the specified amount of data via WebRTC datachannels.</p> + <p>This page generates and sends the specified amount of data via WebRTC datachannels.</p> - <p>To accomplish this in an interoperable way, the data is split into chunks which are then transferred via the datachannel. The datachannel is reliable and ordered by default which is well-suited to filetransfers.</p> + <p>To accomplish this in an interoperable way, the data is split into chunks which are then transferred via the + datachannel. The datachannel is reliable and ordered by default which is well-suited to filetransfers.</p> - <p>Send and receive progress is monitored using HTML5 <i>progress</i> elements.</p> + <p>Send and receive progress is monitored using HTML5 <i>progress</i> elements.</p> </section> <section> - <div id="button"> - <button id="sendTheData" type="button">Generate and send data</button> - </div> - <div class="input"> - <input type="number" id="megsToSend" min="1" name="megs" value="128"/> - <label for="megsToSend">MB</label> - <div id="errorMsg"></div> - </div> - <div class="input"> - <input type="checkbox" id="ordered" checked> - <label for="ordered">Ordered mode</label> - </div> - <div class="progress"> - <div class="label">Send progress: </div> - <progress id="sendProgress" max="0" value="0"></progress> - </div> + <div id="button"> + <button id="sendTheData" type="button">Generate and send data</button> + </div> + <div class="input"> + <input type="number" id="megsToSend" min="1" name="megs" value="16"/> + <label for="megsToSend">MB <b>(warning: very large values will potentially cause memory problems)</b></label> + <div id="errorMsg"></div> + </div> + <div class="input"> + <input type="checkbox" id="ordered" checked> + <label for="ordered">Ordered mode</label> + </div> + <div class="progress"> + <div class="label">Send progress:</div> + <progress id="sendProgress" max="0" value="0"></progress> + </div> - <div class="progress"> - <div class="label">Receive progress: </div> - <progress id="receiveProgress" max="0" value="0"></progress> - </div> + <div class="progress"> + <div class="label">Receive progress:</div> + <progress id="receiveProgress" max="0" value="0"></progress> + </div> + + <div> + <span id="transferStatus"></span> + </div> </section> <section> - <p>View the console to see logging.</p> + <p>View the console to see logging.</p> - <p>The <code>RTCPeerConnection</code> objects <code>localConnection</code> and <code>remoteConnection</code> are in global scope, so you can inspect them in the console as well.</p> + <p>The <code>RTCPeerConnection</code> objects <code>localConnection</code> and <code>remoteConnection</code> are + in global scope, so you can inspect them in the console as well.</p> - <p>For more information about RTCDataChannel, see <a href="http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-rtcdatachannel" title="RTCDataChannel section of HTML5 Rocks article about WebRTC">Getting Started With WebRTC</a>.</p> + <p>For more information about RTCDataChannel, see <a + href="http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-rtcdatachannel" + title="RTCDataChannel section of HTML5 Rocks article about WebRTC">Getting Started With WebRTC</a>.</p> </section> - <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/datachannel/datatransfer" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> - </div> + <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/datachannel/datatransfer" + title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> +</div> <script src="datatransfer.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/datatransfer.js b/tools/perf/page_sets/webrtc_cases/datatransfer.js index 7c50507..fa589365 100644 --- a/tools/perf/page_sets/webrtc_cases/datatransfer.js +++ b/tools/perf/page_sets/webrtc_cases/datatransfer.js
@@ -4,168 +4,162 @@ * found in the LICENSE file. */ 'use strict'; +const MAX_CHUNK_SIZE = 262144; -var localConnection; -var remoteConnection; -var sendChannel; -var receiveChannel; -var pcConstraint; -var megsToSend = document.querySelector('input#megsToSend'); -var sendButton = document.querySelector('button#sendTheData'); -var orderedCheckbox = document.querySelector('input#ordered'); -var sendProgress = document.querySelector('progress#sendProgress'); -var receiveProgress = document.querySelector('progress#receiveProgress'); -var errorMessage = document.querySelector('div#errorMsg'); +let localConnection; +let remoteConnection; +let sendChannel; +let receiveChannel; +let chunkSize; +let lowWaterMark; +let highWaterMark; +let dataString; +let timeoutHandle = null; +const megsToSend = document.querySelector('input#megsToSend'); +const sendButton = document.querySelector('button#sendTheData'); +const orderedCheckbox = document.querySelector('input#ordered'); +const sendProgress = document.querySelector('progress#sendProgress'); +const receiveProgress = document.querySelector('progress#receiveProgress'); +const errorMessage = document.querySelector('div#errorMsg'); +const transferStatus = document.querySelector('span#transferStatus'); -var receivedSize = 0; -var bytesToSend = 0; +let bytesToSend = 0; +let totalTimeUsedInSend = 0; +let numberOfSendCalls = 0; +let maxTimeUsedInSend = 0; +let sendStartTime = 0; -sendButton.onclick = createConnection; +sendButton.addEventListener('click', createConnection); // Prevent data sent to be set to 0. -megsToSend.addEventListener('change', function(e) { - if (this.value <= 0) { +megsToSend.addEventListener('change', function() { + const number = this.value; + if (Number.isNaN(number)) { + errorMessage.innerHTML = `Invalid value for MB to send: ${number}`; + } else if (number <= 0) { sendButton.disabled = true; errorMessage.innerHTML = '<p>Please enter a number greater than zero.</p>'; + } else if (number > 64) { + sendButton.disabled = true; + errorMessage.innerHTML = '<p>Please enter a number lower or equal than 64.</p>'; } else { errorMessage.innerHTML = ''; sendButton.disabled = false; } }); -function createConnection() { +async function createConnection() { sendButton.disabled = true; megsToSend.disabled = true; - var servers = null; - pcConstraint = null; - bytesToSend = Math.round(megsToSend.value) * 1024 * 1024; + const servers = null; - // Add localConnection to global scope to make it visible - // from the browser console. - window.localConnection = localConnection = new RTCPeerConnection(servers, - pcConstraint); - trace('Created local peer connection object localConnection'); + const number = Number.parseInt(megsToSend.value); + bytesToSend = number * 1024 * 1024; - var dataChannelParams = {ordered: false}; + localConnection = new RTCPeerConnection(servers); + + // Let's make a data channel! + const dataChannelParams = {ordered: false}; if (orderedCheckbox.checked) { dataChannelParams.ordered = true; } + sendChannel = localConnection.createDataChannel('sendDataChannel', dataChannelParams); + sendChannel.addEventListener('open', onSendChannelOpen); + sendChannel.addEventListener('close', onSendChannelClosed); + console.log('Created send data channel: ', sendChannel); - sendChannel = localConnection.createDataChannel( - 'sendDataChannel', dataChannelParams); - sendChannel.binaryType = 'arraybuffer'; - trace('Created send data channel'); + console.log('Created local peer connection object localConnection: ', localConnection); - sendChannel.onopen = onSendChannelStateChange; - sendChannel.onclose = onSendChannelStateChange; - localConnection.onicecandidate = function(e) { - onIceCandidate(localConnection, e); - }; + localConnection.addEventListener('icecandidate', e => onIceCandidate(localConnection, e)); - localConnection.createOffer().then( - gotDescription1, - onCreateSessionDescriptionError - ); + remoteConnection = new RTCPeerConnection(servers); + remoteConnection.addEventListener('icecandidate', e => onIceCandidate(remoteConnection, e)); + remoteConnection.addEventListener('datachannel', receiveChannelCallback); - // Add remoteConnection to global scope to make it visible - // from the browser console. - window.remoteConnection = remoteConnection = new RTCPeerConnection(servers, - pcConstraint); - trace('Created remote peer connection object remoteConnection'); - - remoteConnection.onicecandidate = function(e) { - onIceCandidate(remoteConnection, e); - }; - remoteConnection.ondatachannel = receiveChannelCallback; -} - -function onCreateSessionDescriptionError(error) { - trace('Failed to create session description: ' + error.toString()); -} - -function randomAsciiString(length) { - var result = ''; - for (var i = 0; i < length; i++) { - // Visible ASCII chars are between 33 and 126. - result += String.fromCharCode(33 + Math.random() * 93); + try { + const localOffer = await localConnection.createOffer(); + await handleLocalDescription(localOffer); + } catch (e) { + console.error('Failed to create session description: ', e); } - return result; + + transferStatus.innerHTML = 'Peer connection setup complete.'; } -function sendGeneratedData() { +function sendData() { + // Stop scheduled timer if any (part of the workaround introduced below) + if (timeoutHandle !== null) { + clearTimeout(timeoutHandle); + timeoutHandle = null; + } + + let bufferedAmount = sendChannel.bufferedAmount; + while (sendProgress.value < sendProgress.max) { + transferStatus.innerText = 'Sending data...'; + const timeBefore = performance.now(); + sendChannel.send(dataString); + const timeUsed = performance.now() - timeBefore; + if (timeUsed > maxTimeUsedInSend) { + maxTimeUsedInSend = timeUsed; + totalTimeUsedInSend += timeUsed; + } + numberOfSendCalls += 1; + bufferedAmount += chunkSize; + sendProgress.value += chunkSize; + + // Pause sending if we reach the high water mark + if (bufferedAmount >= highWaterMark) { + // This is a workaround due to the bug that all browsers are incorrectly calculating the + // amount of buffered data. Therefore, the 'bufferedamountlow' event would not fire. + if (sendChannel.bufferedAmount < lowWaterMark) { + timeoutHandle = setTimeout(() => sendData(), 0); + } + console.log(`Paused sending, buffered amount: ${bufferedAmount} (announced: ${sendChannel.bufferedAmount})`); + break; + } + } + + if (sendProgress.value === sendProgress.max) { + transferStatus.innerHTML = 'Data transfer completed successfully!'; + } +} + +function startSendingData() { + transferStatus.innerHTML = 'Start sending data.'; sendProgress.max = bytesToSend; receiveProgress.max = sendProgress.max; sendProgress.value = 0; receiveProgress.value = 0; + sendStartTime = performance.now(); + maxTimeUsedInSend = 0; + totalTimeUsedInSend = 0; + numberOfSendCalls = 0; + sendData(); +} - var chunkSize = 16384; - var stringToSendRepeatedly = randomAsciiString(chunkSize); - var bufferFullThreshold = 5 * chunkSize; - var usePolling = true; - if (typeof sendChannel.bufferedAmountLowThreshold === 'number') { - trace('Using the bufferedamountlow event for flow control'); - usePolling = false; - - // Reduce the buffer fullness threshold, since we now have more efficient - // buffer management. - bufferFullThreshold = chunkSize / 2; - - // This is "overcontrol": our high and low thresholds are the same. - sendChannel.bufferedAmountLowThreshold = bufferFullThreshold; +function maybeReset() { + if (localConnection === null && remoteConnection === null) { + sendButton.disabled = false; + megsToSend.disabled = false; } - // Listen for one bufferedamountlow event. - var listener = function() { - sendChannel.removeEventListener('bufferedamountlow', listener); - sendAllData(); - }; - var sendAllData = function() { - // Try to queue up a bunch of data and back off when the channel starts to - // fill up. We don't setTimeout after each send since this lowers our - // throughput quite a bit (setTimeout(fn, 0) can take hundreds of milli- - // seconds to execute). - while (sendProgress.value < sendProgress.max) { - if (sendChannel.bufferedAmount > bufferFullThreshold) { - if (usePolling) { - setTimeout(sendAllData, 250); - } else { - sendChannel.addEventListener('bufferedamountlow', listener); - } - return; - } - sendProgress.value += chunkSize; - sendChannel.send(stringToSendRepeatedly); - } - }; - setTimeout(sendAllData, 0); } -function closeDataChannels() { - trace('Closing data channels'); - sendChannel.close(); - trace('Closed data channel with label: ' + sendChannel.label); - receiveChannel.close(); - trace('Closed data channel with label: ' + receiveChannel.label); - localConnection.close(); - remoteConnection.close(); - localConnection = null; - remoteConnection = null; - trace('Closed peer connections'); -} - -function gotDescription1(desc) { +async function handleLocalDescription(desc) { localConnection.setLocalDescription(desc); - trace('Offer from localConnection \n' + desc.sdp); + console.log('Offer from localConnection:\n', desc.sdp); remoteConnection.setRemoteDescription(desc); - remoteConnection.createAnswer().then( - gotDescription2, - onCreateSessionDescriptionError - ); + try { + const remoteAnswer = await remoteConnection.createAnswer(); + handleRemoteAnswer(remoteAnswer); + } catch (e) { + console.error('Error when creating remote answer: ', e); + } } -function gotDescription2(desc) { +function handleRemoteAnswer(desc) { remoteConnection.setLocalDescription(desc); - trace('Answer from remoteConnection \n' + desc.sdp); + console.log('Answer from remoteConnection:\n', desc.sdp); localConnection.setRemoteDescription(desc); } @@ -173,57 +167,76 @@ return (pc === localConnection) ? remoteConnection : localConnection; } -function getName(pc) { - return (pc === localConnection) ? 'localPeerConnection' : - 'remotePeerConnection'; -} - -function onIceCandidate(pc, event) { - getOtherPc(pc).addIceCandidate(event.candidate) - .then( - function() { - onAddIceCandidateSuccess(pc); - }, - function(err) { - onAddIceCandidateError(pc, err); - } - ); - trace(getName(pc) + ' ICE candidate: \n' + (event.candidate ? - event.candidate.candidate : '(null)')); -} - -function onAddIceCandidateSuccess() { - trace('AddIceCandidate success.'); -} - -function onAddIceCandidateError(error) { - trace('Failed to add Ice Candidate: ' + error.toString()); +async function onIceCandidate(pc, event) { + const candidate = event.candidate; + if (candidate === null) { + return; + } // Ignore null candidates + try { + await getOtherPc(pc).addIceCandidate(candidate); + console.log('AddIceCandidate successful: ', candidate); + } catch (e) { + console.error('Failed to add Ice Candidate: ', e); + } } function receiveChannelCallback(event) { - trace('Receive Channel Callback'); + console.log('Receive Channel Callback'); receiveChannel = event.channel; receiveChannel.binaryType = 'arraybuffer'; - receiveChannel.onmessage = onReceiveMessageCallback; - - receivedSize = 0; + receiveChannel.addEventListener('close', onReceiveChannelClosed); + receiveChannel.addEventListener('message', onReceiveMessageCallback); } function onReceiveMessageCallback(event) { - receivedSize += event.data.length; - receiveProgress.value = receivedSize; + receiveProgress.value += event.data.length; - if (receivedSize === bytesToSend) { - closeDataChannels(); - sendButton.disabled = false; - megsToSend.disabled = false; + // Workaround for a bug in Chrome which prevents the closing event from being raised by the + // remote side. Also a workaround for Firefox which does not send all pending data when closing + // the channel. + if (receiveProgress.value === receiveProgress.max) { + sendChannel.close(); + receiveChannel.close(); } } -function onSendChannelStateChange() { - var readyState = sendChannel.readyState; - trace('Send channel state is: ' + readyState); - if (readyState === 'open') { - sendGeneratedData(); - } +function onSendChannelOpen() { + console.log('Send channel is open'); + + chunkSize = Math.min(localConnection.sctp.maxMessageSize, MAX_CHUNK_SIZE); + console.log('Determined chunk size: ', chunkSize); + dataString = new Array(chunkSize).fill('X').join(''); + lowWaterMark = chunkSize; // A single chunk + highWaterMark = Math.max(chunkSize * 8, 1048576); // 8 chunks or at least 1 MiB + console.log('Send buffer low water threshold: ', lowWaterMark); + console.log('Send buffer high water threshold: ', highWaterMark); + sendChannel.bufferedAmountLowThreshold = lowWaterMark; + sendChannel.addEventListener('bufferedamountlow', (e) => { + console.log('BufferedAmountLow event:', e); + sendData(); + }); + + startSendingData(); +} + +function onSendChannelClosed() { + console.log('Send channel is closed'); + localConnection.close(); + localConnection = null; + console.log('Closed local peer connection'); + maybeReset(); + console.log('Average time spent in send() (ms): ' + + totalTimeUsedInSend / numberOfSendCalls); + console.log('Max time spent in send() (ms): ' + maxTimeUsedInSend); + const spentTime = performance.now() - sendStartTime; + console.log('Total time spent: ' + spentTime); + console.log('MBytes/Sec: ' + (bytesToSend / 1000) / spentTime); +} + +function onReceiveChannelClosed() { + console.log('Receive channel is closed'); + remoteConnection.close(); + remoteConnection = null; + console.log('Closed remote peer connection'); + maybeReset(); }
diff --git a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.html b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.html index dff5a91..5a7eac2 100644 --- a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.html +++ b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.html
@@ -40,6 +40,5 @@ <script src="multiple-peerconnections.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js index ef93404..3af6c63 100644 --- a/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js +++ b/tools/perf/page_sets/webrtc_cases/multiple-peerconnections.js
@@ -17,7 +17,7 @@ startTestButton.onclick = startTest; function logError(err) { - console.error(err); + console.err(err); } function addNewVideoElement() {
diff --git a/tools/perf/page_sets/webrtc_cases/pause-play.html b/tools/perf/page_sets/webrtc_cases/pause-play.html index 5b5825d..84dc4e4 100644 --- a/tools/perf/page_sets/webrtc_cases/pause-play.html +++ b/tools/perf/page_sets/webrtc_cases/pause-play.html
@@ -12,6 +12,5 @@ <table border="0" id="test-table"></table> <script src="pause-play.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/resolution.html b/tools/perf/page_sets/webrtc_cases/resolution.html index e92e0799..5f02eec 100644 --- a/tools/perf/page_sets/webrtc_cases/resolution.html +++ b/tools/perf/page_sets/webrtc_cases/resolution.html
@@ -8,73 +8,97 @@ <head> - <base target="_blank"> + <base target="_blank"> - <title>getUserMedia: select resolution</title> + <title>getUserMedia: select resolution</title> - <style> - body, html { - height: 100%; - } + <style> + body, html { + height: 100%; + } - button { - margin: 0 10px 20px 0; - width: 90px; - } + button { + margin: 0 10px 20px 0; + width: 90px; + } - div#buttons { - margin: 0 0 1em 0; - } + div#buttons { + margin: 0 0 1em 0; + } - div#container { - max-width: 100%; - } + div#container { + max-width: 100%; + } - p#dimensions { - height: 1em; - margin: 0 0 1.5em 0; - } + #errormessage { + display: none; + font-size: 300%; + } - video { - background: none; - height: auto; - width: auto; - } - </style> + #videoblock { + display: none; + } + + p#dimensions { + height: 1em; + margin: 0 0 1.5em 0; + } + + video { + background: none; + height: auto; + width: auto; + } + </style> </head> <body> - <div id="container"> +<div id="container"> - <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>getUserMedia: select resolution</span></h1> + <h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a> <span>getUserMedia: select resolution</span> + </h1> <p></p> - <p>This example uses <a href="https://w3c.github.io/mediacapture-main/getusermedia.html#media-track-constraints" title="W3C getusermedia specification - constraints section">constraints</a>.</p> + <p>This example uses <a href="https://w3c.github.io/mediacapture-main/getusermedia.html#media-track-constraints" + title="W3C getusermedia specification - constraints section">constraints</a>.</p> <p>Click a button to call <code>getUserMedia()</code> with appropriate resolution.</p> <div id="buttons"> - <button id="qvga">QVGA</button> - <button id="vga">VGA</button> - <button id="hd">HD</button> - <button id="full-hd">Full HD</button> + <button id="qvga">QVGA</button> + <button id="vga">VGA</button> + <button id="hd">HD</button> + <button id="full-hd">Full HD</button> + <button id="fourK">4K</button> + <button id="eightK">8K</button> </div> - <p id="dimensions"></p> + <div id="videoblock"> + <p id="dimensions"></p> - <video id="gum-res-local" autoplay></video> + <video id="gum-res-local" playsinline autoplay></video> + <div id="width"> + <label>Width <span></span>px:</label> + <input type="range" min="0" max="7680" value="0"> + </div> + <input id="sizelock" type="checkbox">Lock video size<br> + <input id="aspectlock" type="checkbox">Lock aspect ratio<br> + </div> + <p id="errormessage"></p> - <p>For more information, see <a href="http://www.html5rocks.com/en/tutorials/getusermedia/intro/" title="Media capture article by Eric Bidelman on HTML5 Rocks">Capturing Audio & Video in HTML5</a> on HTML5 Rocks.</p> + <p>For more information, see <a href="http://www.html5rocks.com/en/tutorials/getusermedia/intro/" + title="Media capture article by Eric Bidelman on HTML5 Rocks">Capturing Audio & + Video in HTML5</a> on HTML5 Rocks.</p> - <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/resolution" title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> - </div> + <a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/resolution" + title="View source for this page on GitHub" id="viewSource">View source on GitHub</a> +</div> <script src="resolution.js"></script> -<script src="adapter.js"></script> -<script src="common.js"></script> +<script src="adapter-latest.js"></script> </body></html>
diff --git a/tools/perf/page_sets/webrtc_cases/resolution.js b/tools/perf/page_sets/webrtc_cases/resolution.js index 4b807b0..0f275bb 100644 --- a/tools/perf/page_sets/webrtc_cases/resolution.js +++ b/tools/perf/page_sets/webrtc_cases/resolution.js
@@ -5,74 +5,177 @@ */ 'use strict'; -var dimensions = document.querySelector('#dimensions'); -var video = document.querySelector('video'); -var stream; +const dimensions = document.querySelector('#dimensions'); +const video = document.querySelector('video'); +let stream; -var vgaButton = document.querySelector('#vga'); -var qvgaButton = document.querySelector('#qvga'); -var hdButton = document.querySelector('#hd'); -var fullHdButton = document.querySelector('#full-hd'); +const vgaButton = document.querySelector('#vga'); +const qvgaButton = document.querySelector('#qvga'); +const hdButton = document.querySelector('#hd'); +const fullHdButton = document.querySelector('#full-hd'); +const fourKButton = document.querySelector('#fourK'); +const eightKButton = document.querySelector('#eightK'); -vgaButton.onclick = function() { +const videoblock = document.querySelector('#videoblock'); +const messagebox = document.querySelector('#errormessage'); + +const widthInput = document.querySelector('div#width input'); +const widthOutput = document.querySelector('div#width span'); +const aspectLock = document.querySelector('#aspectlock'); +const sizeLock = document.querySelector('#sizelock'); + +let currentWidth = 0; +let currentHeight = 0; + +vgaButton.onclick = () => { getMedia(vgaConstraints); }; -qvgaButton.onclick = function() { +qvgaButton.onclick = () => { getMedia(qvgaConstraints); }; -hdButton.onclick = function() { +hdButton.onclick = () => { getMedia(hdConstraints); }; -fullHdButton.onclick = function() { +fullHdButton.onclick = () => { getMedia(fullHdConstraints); }; -var qvgaConstraints = { +fourKButton.onclick = () => { + getMedia(fourKConstraints); +}; + +eightKButton.onclick = () => { + getMedia(eightKConstraints); +}; + +const qvgaConstraints = { video: {width: {exact: 320}, height: {exact: 240}} }; -var vgaConstraints = { +const vgaConstraints = { video: {width: {exact: 640}, height: {exact: 480}} }; -var hdConstraints = { +const hdConstraints = { video: {width: {exact: 1280}, height: {exact: 720}} }; -var fullHdConstraints = { +const fullHdConstraints = { video: {width: {exact: 1920}, height: {exact: 1080}} }; +const fourKConstraints = { + video: {width: {exact: 4096}, height: {exact: 2160}} +}; + +const eightKConstraints = { + video: {width: {exact: 7680}, height: {exact: 4320}} +}; + function gotStream(mediaStream) { - window.stream = mediaStream; // stream available to console + stream = window.stream = mediaStream; // stream available to console video.srcObject = mediaStream; -} - -function displayVideoDimensions() { - if (!video.videoWidth) { - setTimeout(displayVideoDimensions, 500); + messagebox.style.display = 'none'; + videoblock.style.display = 'block'; + const track = mediaStream.getVideoTracks()[0]; + const constraints = track.getConstraints(); + console.log('Result constraints: ' + JSON.stringify(constraints)); + if (constraints && constraints.width && constraints.width.exact) { + widthInput.value = constraints.width.exact; + widthOutput.textContent = constraints.width.exact; + } else if (constraints && constraints.width && constraints.width.min) { + widthInput.value = constraints.width.min; + widthOutput.textContent = constraints.width.min; } - dimensions.innerHTML = 'Actual video dimensions: ' + video.videoWidth + - 'x' + video.videoHeight + 'px.'; } -video.onloadedmetadata = displayVideoDimensions; +function errorMessage(who, what) { + const message = who + ': ' + what; + messagebox.innerText = message; + messagebox.style.display = 'block'; + console.log(message); +} + +function clearErrorMessage() { + messagebox.style.display = 'none'; +} + +function displayVideoDimensions(whereSeen) { + if (video.videoWidth) { + dimensions.innerText = 'Actual video dimensions: ' + video.videoWidth + + 'x' + video.videoHeight + 'px.'; + if (currentWidth !== video.videoWidth || + currentHeight !== video.videoHeight) { + console.log(whereSeen + ': ' + dimensions.innerText); + currentWidth = video.videoWidth; + currentHeight = video.videoHeight; + } + } else { + dimensions.innerText = 'Video not ready'; + } +} + +video.onloadedmetadata = () => { + displayVideoDimensions('loadedmetadata'); +}; + +video.onresize = () => { + displayVideoDimensions('resize'); +}; + +function constraintChange(e) { + widthOutput.textContent = e.target.value; + const track = window.stream.getVideoTracks()[0]; + let constraints; + if (aspectLock.checked) { + constraints = { + width: {exact: e.target.value}, + aspectRatio: { + exact: video.videoWidth / video.videoHeight + } + }; + } else { + constraints = {width: {exact: e.target.value}}; + } + clearErrorMessage(); + console.log('applying ' + JSON.stringify(constraints)); + track.applyConstraints(constraints) + .then(() => { + console.log('applyConstraint success'); + displayVideoDimensions('applyConstraints'); + }) + .catch(err => { + errorMessage('applyConstraints', err.name); + }); +} + +widthInput.onchange = constraintChange; + +sizeLock.onchange = () => { + if (sizeLock.checked) { + console.log('Setting fixed size'); + video.style.width = '100%'; + } else { + console.log('Setting auto size'); + video.style.width = 'auto'; + } +}; function getMedia(constraints) { if (stream) { - stream.getTracks().forEach(function(track) { + stream.getTracks().forEach(track => { track.stop(); }); } + clearErrorMessage(); + videoblock.style.display = 'none'; navigator.mediaDevices.getUserMedia(constraints) - .then(gotStream) - .catch(function(e) { - var message = 'getUserMedia error: ' + e.name; - alert(message); - console.log(message); - }); + .then(gotStream) + .catch(e => { + errorMessage('getUserMedia', e.message, e.name); + }); }
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index db06d8d..e4f8453f 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -198,7 +198,7 @@ <item id="ntp_icon_source" added_in_milestone="69" hash_code="29197139" type="0" content_hash_code="16399294" os_list="linux,windows" file_path="chrome/browser/search/ntp_icon_source.cc"/> <item id="ntp_snippets_fetch" added_in_milestone="62" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/> <item id="nux_ntp_background_preview" added_in_milestone="74" hash_code="124847649" type="0" content_hash_code="31404656" os_list="linux,windows" file_path="chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc"/> - <item id="oauth2_access_token_fetcher" added_in_milestone="62" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/oauth2_access_token_fetcher_impl.cc"/> + <item id="oauth2_access_token_fetcher" added_in_milestone="62" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/gaia_access_token_fetcher.cc"/> <item id="oauth2_api_call_flow" added_in_milestone="65" hash_code="29188932" type="2" content_hash_code="108831236" os_list="linux,windows" policy_fields="-1" file_path="google_apis/gaia/oauth2_api_call_flow.cc"/> <item id="oauth2_mint_token_flow" added_in_milestone="62" hash_code="1112842" type="1" second_id="29188932" content_hash_code="91581432" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="google_apis/gaia/oauth2_mint_token_flow.cc"/> <item id="ocsp_start_url_loader" added_in_milestone="81" hash_code="3646641" type="0" deprecated="2020-04-28" content_hash_code="106270072" file_path=""/>
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc index ab23bce..73017647 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc +++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -7,6 +7,7 @@ #include <cstdint> #include "base/check.h" +#include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_constants.h" @@ -160,7 +161,7 @@ received_data_ = std::make_unique<OSExchangeData>( std::make_unique<OSExchangeDataProviderNonBacked>()); last_drag_location_ = location; - HandleUnprocessedMimeTypes(); + HandleUnprocessedMimeTypes(base::TimeTicks::Now()); } } @@ -281,21 +282,23 @@ // more unprocessed mime types on the |unprocessed_mime_types_| queue. Once this // process is finished, OnDataTransferFinished is called to deliver the // |received_data_| to the drop handler. -void WaylandDataDragController::HandleUnprocessedMimeTypes() { +void WaylandDataDragController::HandleUnprocessedMimeTypes( + base::TimeTicks start_time) { DCHECK_EQ(state_, State::kTransferring); std::string mime_type = GetNextUnprocessedMimeType(); if (mime_type.empty() || is_leave_pending_) { - OnDataTransferFinished(std::move(received_data_)); + OnDataTransferFinished(start_time, std::move(received_data_)); } else { DCHECK(data_offer_); data_device_->RequestData( data_offer_.get(), mime_type, base::BindOnce(&WaylandDataDragController::OnMimeTypeDataTransferred, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), start_time)); } } void WaylandDataDragController::OnMimeTypeDataTransferred( + base::TimeTicks start_time, PlatformClipboard::Data contents) { DCHECK_EQ(state_, State::kTransferring); DCHECK(contents); @@ -306,10 +309,11 @@ unprocessed_mime_types_.pop_front(); // Continue reading data for other negotiated mime types. - HandleUnprocessedMimeTypes(); + HandleUnprocessedMimeTypes(start_time); } void WaylandDataDragController::OnDataTransferFinished( + base::TimeTicks start_time, std::unique_ptr<OSExchangeData> received_data) { unprocessed_mime_types_.clear(); state_ = State::kIdle; @@ -329,6 +333,9 @@ return; } + UMA_HISTOGRAM_TIMES("Event.WaylandDragDrop.IncomingDataTransferTime", + base::TimeTicks::Now() - start_time); + PropagateOnDragEnter(last_drag_location_, std::move(received_data)); }
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h index 79589467..efb6965 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h +++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -105,9 +105,11 @@ void Offer(const OSExchangeData& data, int operation); void CreateIconSurfaceIfNeeded(const OSExchangeData& data); - void HandleUnprocessedMimeTypes(); - void OnMimeTypeDataTransferred(PlatformClipboard::Data contents); + void HandleUnprocessedMimeTypes(base::TimeTicks start_time); + void OnMimeTypeDataTransferred(base::TimeTicks start_time, + PlatformClipboard::Data contents); void OnDataTransferFinished( + base::TimeTicks start_time, std::unique_ptr<ui::OSExchangeData> received_data); std::string GetNextUnprocessedMimeType(); // Calls the window's OnDragEnter with the given location and data,
diff --git a/ui/webui/resources/js/cr/ui/list.js b/ui/webui/resources/js/cr/ui/list.js index d68e316..d65b21a 100644 --- a/ui/webui/resources/js/cr/ui/list.js +++ b/ui/webui/resources/js/cr/ui/list.js
@@ -1401,9 +1401,6 @@ function handleMouseDown(e) { e.target = /** @type {!HTMLElement} */ (e.target); const listItem = this.getListItemAncestor(e.target); - if (!listItem) { - return; - } const wasSelected = listItem && listItem.selected; this.handlePointerDownUp_(e);
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java index 6746cbe8..392038b8 100644 --- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java +++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java
@@ -21,6 +21,8 @@ import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.weblayer.Browser; import org.chromium.weblayer.NavigateParams; +import org.chromium.weblayer.Navigation; +import org.chromium.weblayer.NavigationCallback; import org.chromium.weblayer.Tab; import org.chromium.weblayer.TabListCallback; import org.chromium.weblayer.shell.InstrumentationActivity; @@ -45,6 +47,13 @@ } } + private static final boolean EXPECT_NAVIGATION_COMPLETION = true; + private static final boolean EXPECT_NAVIGATION_FAILURE = false; + private static final boolean RESULTS_IN_EXTERNAL_INTENT = true; + private static final boolean DOESNT_RESULT_IN_EXTERNAL_INTENT = false; + private static final boolean RESULTS_IN_USER_DECIDING_EXTERNAL_INTENT = true; + private static final boolean DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT = false; + private static final String ABOUT_BLANK_URL = "about:blank"; private static final String CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER = "weblayer://weblayertest/intent"; @@ -126,6 +135,80 @@ } } + /* + * Navigates to |urlToNavigateTo| and waits for a completed/failed navigation to |urlToWaitFor| + * as appropriate. In the callback verifies that the values of the relevant params on the + * Navigation match the passed-in expected values. + */ + private void navigateAndCheckExternalIntentParams(String urlToNavigateTo, String urlToWaitFor, + boolean expectNavigationCompletion, boolean resultsInExternalIntent, + boolean resultsInUserDecidingIntentLaunch) throws Throwable { + Tab tab = mActivityTestRule.getActivity().getTab(); + + CallbackHelper navigationCompletedCallbackHelper = new CallbackHelper(); + CallbackHelper navigationFailedCallbackHelper = new CallbackHelper(); + + NavigationCallback navigationCallback = new NavigationCallback() { + @Override + public void onNavigationCompleted(Navigation navigation) { + String url = navigation.getUri().toString(); + if (!url.equals(urlToWaitFor)) return; + + Assert.assertEquals(true, expectNavigationCompletion); + + // A navigation should never be expected to both complete and result in an external + // intent. + Assert.assertEquals(false, resultsInExternalIntent); + Assert.assertEquals(false, navigation.wasIntentLaunched()); + Assert.assertEquals(false, resultsInUserDecidingIntentLaunch); + Assert.assertEquals(false, navigation.isUserDecidingIntentLaunch()); + + navigationCompletedCallbackHelper.notifyCalled(); + } + + @Override + public void onNavigationFailed(Navigation navigation) { + String url = navigation.getUri().toString(); + if (!url.equals(urlToWaitFor)) return; + + Assert.assertEquals(false, expectNavigationCompletion); + + Assert.assertEquals(resultsInExternalIntent, navigation.wasIntentLaunched()); + Assert.assertEquals( + resultsInUserDecidingIntentLaunch, navigation.isUserDecidingIntentLaunch()); + + navigationFailedCallbackHelper.notifyCalled(); + } + }; + + TestThreadUtils.runOnUiThreadBlocking(() -> { + tab.getNavigationController().registerNavigationCallback(navigationCallback); + tab.getNavigationController().navigate(Uri.parse(urlToNavigateTo)); + }); + + if (expectNavigationCompletion) { + navigationCompletedCallbackHelper.waitForFirst(); + } else { + navigationFailedCallbackHelper.waitForFirst(); + } + + TestThreadUtils.runOnUiThreadBlocking(() -> { + tab.getNavigationController().unregisterNavigationCallback(navigationCallback); + }); + } + + /* + * A convenience variant of the above method that navigates to and waits for the same URL. See + * comments on the above method. + */ + private void navigateAndCheckExternalIntentParams(String urlToNavigateTo, + boolean expectNavigationCompletion, boolean resultsInExternalIntent, + boolean resultsInUserDecidingIntentLaunch) throws Throwable { + navigateAndCheckExternalIntentParams(urlToNavigateTo, urlToNavigateTo, + expectNavigationCompletion, resultsInExternalIntent, + resultsInUserDecidingIntentLaunch); + } + /** * Verifies that for a navigation to a URI that WebLayer can handle internally, there * is no external intent triggered. @@ -170,6 +253,124 @@ } /** + * Tests that external intent-related navigation params are not set on browser navigations. + */ + @Test + @SmallTest + @MinWebLayerVersion(89) + public void testExternalIntentNavigationParamsNotSetOnBrowserNavigations() throws Throwable { + InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL); + + navigateAndCheckExternalIntentParams(mTestServerSiteUrl, EXPECT_NAVIGATION_COMPLETION, + DOESNT_RESULT_IN_EXTERNAL_INTENT, DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + + // Navigating to an unresolvable intent with a fallback URL should result in a followup + // browser navigation to the fallback URL. + navigateAndCheckExternalIntentParams(mNonResolvableIntentWithFallbackUrl, + mTestServerSiteUrl, EXPECT_NAVIGATION_COMPLETION, DOESNT_RESULT_IN_EXTERNAL_INTENT, + DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + } + + /** + * Tests that Navigation#wasIntentLaunched() is correctly set on embedder navigations that + * resolve to intents. + */ + @Test + @SmallTest + @MinWebLayerVersion(89) + public void testExternalIntentNavigationParamSetOnNavigationsToIntents() throws Throwable { + InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL); + IntentInterceptor intentInterceptor = new IntentInterceptor(); + activity.setIntentInterceptor(intentInterceptor); + + navigateAndCheckExternalIntentParams(INTENT_TO_CHROME_URL, EXPECT_NAVIGATION_FAILURE, + RESULTS_IN_EXTERNAL_INTENT, DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + navigateAndCheckExternalIntentParams(mIntentToChromeWithFallbackUrl, + EXPECT_NAVIGATION_FAILURE, RESULTS_IN_EXTERNAL_INTENT, + DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + navigateAndCheckExternalIntentParams(mRedirectToIntentToChromeURL, INTENT_TO_CHROME_URL, + EXPECT_NAVIGATION_FAILURE, RESULTS_IN_EXTERNAL_INTENT, + DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + navigateAndCheckExternalIntentParams(mRedirectToCustomSchemeUrlWithDefaultExternalHandler, + CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER, EXPECT_NAVIGATION_FAILURE, + RESULTS_IN_EXTERNAL_INTENT, DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + + // A navigation that results in an intent that cannot be launched should still fail, but + // should not have the wasIntentLaunched() parameter set. + navigateAndCheckExternalIntentParams(MALFORMED_INTENT_URL, EXPECT_NAVIGATION_FAILURE, + DOESNT_RESULT_IN_EXTERNAL_INTENT, DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + + // The presence of a fallback URL should not impact the state in the navigation failure + // callback for a navigation that results in an unresolvable intent. + navigateAndCheckExternalIntentParams(mNonResolvableIntentWithFallbackUrl, + EXPECT_NAVIGATION_FAILURE, DOESNT_RESULT_IN_EXTERNAL_INTENT, + DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT); + } + + /** + * Tests that Navigation#isUserDecidingIntentLaunch() is correctly set on embedder navigations + * that resolve to intents in incognito mode. + */ + @Test + @SmallTest + @MinWebLayerVersion(89) + public void testUserDecidingExternalIntentNavigationParamSetOnNavigationsToIntentsInIncognito() + throws Throwable { + Bundle extras = new Bundle(); + extras.putBoolean(InstrumentationActivity.EXTRA_IS_INCOGNITO, true); + mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL, extras); + + navigateAndCheckExternalIntentParams(INTENT_TO_CHROME_URL, EXPECT_NAVIGATION_FAILURE, + DOESNT_RESULT_IN_EXTERNAL_INTENT, RESULTS_IN_USER_DECIDING_EXTERNAL_INTENT); + } + + /** + * Tests that Navigation#wasIntentLaunched() is correctly set on a navigation to an intent that + * is initiated via a link click. + */ + @Test + @SmallTest + @MinWebLayerVersion(89) + public void testExternalIntentNavigationParamSetOnIntentLaunchViaLinkClick() throws Throwable { + // Set up all the prerequisites. + InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL); + IntentInterceptor intentInterceptor = new IntentInterceptor(); + activity.setIntentInterceptor(intentInterceptor); + + Tab tab = mActivityTestRule.getActivity().getTab(); + + CallbackHelper navigationFailureCallbackHelper = new CallbackHelper(); + NavigationCallback navigationCallback = new NavigationCallback() { + @Override + public void onNavigationFailed(Navigation navigation) { + Assert.assertEquals(INTENT_TO_CHROME_URL, navigation.getUri().toString()); + Assert.assertEquals(true, navigation.wasIntentLaunched()); + Assert.assertEquals(false, navigation.isUserDecidingIntentLaunch()); + + navigationFailureCallbackHelper.notifyCalled(); + } + }; + TestThreadUtils.runOnUiThreadBlocking(() -> { + tab.getNavigationController().registerNavigationCallback(navigationCallback); + }); + + // Navigate to a URL that has a link to an intent, click on the link, and verify via the + // callback that the navigation to the intent fails with the expected state set. + String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_CHROME_IN_SAME_TAB_FILE); + mActivityTestRule.navigateAndWait(url); + mActivityTestRule.executeScriptSync( + "document.onclick = function() {document.getElementById('link').click()}", + true /* useSeparateIsolate */); + EventUtils.simulateTouchCenterOfView( + mActivityTestRule.getActivity().getWindow().getDecorView()); + navigationFailureCallbackHelper.waitForFirst(); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + tab.getNavigationController().unregisterNavigationCallback(navigationCallback); + }); + } + + /** * Tests that a navigation that redirects to an external intent results in the external intent * being launched. */
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java index 7a9a730..6a2f3e64 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/InterceptNavigationDelegateClientImpl.java
@@ -10,6 +10,9 @@ import org.chromium.base.ContextUtils; import org.chromium.components.external_intents.AuthenticatorNavigationInterceptor; import org.chromium.components.external_intents.ExternalNavigationHandler; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingAsyncActionType; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult; +import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResultType; import org.chromium.components.external_intents.InterceptNavigationDelegateClient; import org.chromium.components.external_intents.InterceptNavigationDelegateImpl; import org.chromium.components.external_intents.RedirectHandler; @@ -135,6 +138,33 @@ } } + @Override + public void onDecisionReachedForNavigation( + NavigationParams params, OverrideUrlLoadingResult overrideUrlLoadingResult) { + NavigationImpl navigation = + mTab.getNavigationControllerImpl().getNavigationImplFromId(params.navigationId); + + // As the navigation is still ongoing at this point there should be a NavigationImpl + // instance for it. + assert navigation != null; + + switch (overrideUrlLoadingResult.getResultType()) { + case OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT: + navigation.setIntentLaunched(); + break; + case OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION: + if (overrideUrlLoadingResult.getAsyncActionType() + == OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH) { + navigation.setIsUserDecidingIntentLaunch(); + } + break; + case OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB: + case OverrideUrlLoadingResultType.NO_OVERRIDE: + default: + break; + } + } + static void closeTab(TabImpl tab) { // Prior to 84 the client was not equipped to handle the case of WebLayer initiating the // last tab being closed, so we simply short-circuit out here in that case.
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java index 3151068..705cd25 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
@@ -168,6 +168,12 @@ mNativeNavigationController, index); } + public NavigationImpl getNavigationImplFromId(long id) { + StrictModeWorkaround.apply(); + return NavigationControllerImplJni.get().getNavigationImplFromId( + mNativeNavigationController, id); + } + @CalledByNative private NavigationImpl createNavigation(long nativeNavigationImpl) { return new NavigationImpl(mNavigationControllerClient, nativeNavigationImpl); @@ -294,5 +300,6 @@ String getNavigationEntryDisplayUri(long nativeNavigationControllerImpl, int index); String getNavigationEntryTitle(long nativeNavigationControllerImpl, int index); boolean isNavigationEntrySkippable(long nativeNavigationControllerImpl, int index); + NavigationImpl getNavigationImplFromId(long nativeNavigationControllerImpl, long id); } }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java index 247ceeec..a3d9e82 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
@@ -29,6 +29,14 @@ // WARNING: NavigationImpl may outlive the native side, in which case this member is set to 0. private long mNativeNavigationImpl; + // Set to true if/when it is determined that an external intent was launched for this + // navigation. + private boolean mIntentLaunched; + + // Set to true if/when it is determined that this navigation result in UI being presented to the + // user via which the user will determine whether an intent should be launched. + private boolean mIsUserDecidingIntentLaunch; + public NavigationImpl(INavigationControllerClient client, long nativeNavigationImpl) { mNativeNavigationImpl = nativeNavigationImpl; try { @@ -141,6 +149,16 @@ } @Override + public boolean wasIntentLaunched() { + return mIntentLaunched; + } + + @Override + public boolean isUserDecidingIntentLaunch() { + return mIsUserDecidingIntentLaunch; + } + + @Override public boolean wasStopCalled() { StrictModeWorkaround.apply(); throwIfNativeDestroyed(); @@ -161,6 +179,14 @@ return NavigationImplJni.get().isReload(mNativeNavigationImpl); } + public void setIntentLaunched() { + mIntentLaunched = true; + } + + public void setIsUserDecidingIntentLaunch() { + mIsUserDecidingIntentLaunch = true; + } + private void throwIfNativeDestroyed() { if (mNativeNavigationImpl == 0) { throw new IllegalStateException("Using Navigation after native destroyed");
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java index 88e3b88..f04f0ab 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/TabImpl.java
@@ -511,6 +511,10 @@ return mWebContents; } + public NavigationControllerImpl getNavigationControllerImpl() { + return mNavigationController; + } + // Public for tests. @VisibleForTesting public long getNativeTab() {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl index 5c94e34..de8dcb7 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl +++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
@@ -33,4 +33,8 @@ // @since 86 boolean isPageInitiated() = 11; boolean isReload() = 12; + + // @since 89 + boolean wasIntentLaunched() = 13; + boolean isUserDecidingIntentLaunch() = 14; }
diff --git a/weblayer/browser/navigation_controller_impl.cc b/weblayer/browser/navigation_controller_impl.cc index 51baf80..800cb57 100644 --- a/weblayer/browser/navigation_controller_impl.cc +++ b/weblayer/browser/navigation_controller_impl.cc
@@ -216,6 +216,13 @@ int index) { return IsNavigationEntrySkippable(index); } + +base::android::ScopedJavaGlobalRef<jobject> +NavigationControllerImpl::GetNavigationImplFromId(JNIEnv* env, int64_t id) { + auto* navigation_impl = GetNavigationImplFromId(id); + return navigation_impl ? navigation_impl->java_navigation() : nullptr; +} + #endif void NavigationControllerImpl::WillRedirectRequest(
diff --git a/weblayer/browser/navigation_controller_impl.h b/weblayer/browser/navigation_controller_impl.h index 8a2669ec..5b6d5ebf 100644 --- a/weblayer/browser/navigation_controller_impl.h +++ b/weblayer/browser/navigation_controller_impl.h
@@ -77,6 +77,9 @@ JNIEnv* env, int index); bool IsNavigationEntrySkippable(JNIEnv* env, int index); + base::android::ScopedJavaGlobalRef<jobject> GetNavigationImplFromId( + JNIEnv* env, + int64_t id); #endif bool should_delay_web_contents_deletion() {
diff --git a/weblayer/browser/prefetch_browsertest.cc b/weblayer/browser/prefetch_browsertest.cc index df3bcaf..62ab5ce 100644 --- a/weblayer/browser/prefetch_browsertest.cc +++ b/weblayer/browser/prefetch_browsertest.cc
@@ -4,7 +4,9 @@ #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" +#include "base/synchronization/lock.h" #include "base/test/bind.h" +#include "base/thread_annotations.h" #include "build/build_config.h" #include "components/network_session_configurator/common/network_switches.h" #include "content/public/browser/web_contents.h" @@ -57,6 +59,12 @@ protected: bool prefetch_target_request_seen_ = false; + base::Lock lock_; + + // |requests_| is accessed on the UI thread by the test body and on the IO + // thread by the test server's request handler, so must be guarded by a lock + // to avoid data races. + std::vector<net::test_server::HttpRequest> requests_ GUARDED_BY(lock_); private: void MonitorRequest(const net::test_server::HttpRequest& request) { @@ -80,21 +88,15 @@ // https://crbug.com/922362: When the prefetched request is redirected, DCHECKs // in PrefetchURLLoader::FollowRedirect() failed due to "X-Client-Data" in // removed_headers. Verify that it no longer does. -// TODO(https://crbug.com/1144142): Fails on TSan due to data race. -#if defined(THREAD_SANITIZER) -#define MAYBE_RedirectedPrefetch DISABLED_RedirectedPrefetch -#else -#define MAYBE_RedirectedPrefetch RedirectedPrefetch -#endif -IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, MAYBE_RedirectedPrefetch) { - std::vector<net::test_server::HttpRequest> requests; +IN_PROC_BROWSER_TEST_F(PrefetchBrowserTest, RedirectedPrefetch) { net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); https_server.RegisterRequestHandler(base::BindLambdaForTesting( - [&requests](const net::test_server::HttpRequest& request) + [this](const net::test_server::HttpRequest& request) -> std::unique_ptr<net::test_server::HttpResponse> { auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + base::AutoLock auto_lock(lock_); if (request.relative_url == std::string(kRedirectPrefetchPage)) { - requests.push_back(request); + requests_.push_back(request); response->set_content_type("text/html"); response->set_content( base::StringPrintf("<link rel=\"prefetch\" href=\"%s\" " @@ -102,7 +104,7 @@ kRedirectPrefetchUrl)); return response; } else if (request.relative_url == std::string(kRedirectPrefetchUrl)) { - requests.push_back(request); + requests_.push_back(request); response->set_code(net::HTTP_MOVED_PERMANENTLY); response->AddCustomHeader( "Location", base::StringPrintf("https://example.com:%s%s", @@ -111,7 +113,7 @@ return response; } else if (request.relative_url == std::string(kRedirectedPrefetchUrl)) { - requests.push_back(request); + requests_.push_back(request); return response; } return nullptr; @@ -119,15 +121,21 @@ https_server.ServeFilesFromSourceDirectory( base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); + { + base::AutoLock auto_lock(lock_); + requests_.clear(); + } ASSERT_TRUE(https_server.Start()); GURL url = https_server.GetURL("www.google.com", kRedirectPrefetchPage); EXPECT_TRUE(RunPrefetchExperiment(url, base::ASCIIToUTF16("done"))); - ASSERT_EQ(3U, requests.size()); - - EXPECT_EQ(base::StringPrintf("www.google.com:%u", https_server.port()), - requests[0].headers["Host"]); - EXPECT_EQ(kRedirectPrefetchPage, requests[0].relative_url); + { + base::AutoLock auto_lock(lock_); + ASSERT_EQ(3U, requests_.size()); + EXPECT_EQ(base::StringPrintf("www.google.com:%u", https_server.port()), + requests_[0].headers["Host"]); + EXPECT_EQ(kRedirectPrefetchPage, requests_[0].relative_url); + } } } // namespace weblayer
diff --git a/weblayer/public/java/org/chromium/weblayer/Navigation.java b/weblayer/public/java/org/chromium/weblayer/Navigation.java index e302c50..e312642 100644 --- a/weblayer/public/java/org/chromium/weblayer/Navigation.java +++ b/weblayer/public/java/org/chromium/weblayer/Navigation.java
@@ -145,6 +145,43 @@ } /** + * Whether this navigation resulted in an external intent being launched. Returns false if this + * navigation did not do so, or if that status is not yet known for this navigation. This + * status is determined for a navigation when processing final (post redirect) HTTP response + * headers. This means the only time the embedder can know if the navigation resulted in an + * external intent being launched is in NavigationCallback.onNavigationFailed. + * + * @since 89 + */ + public boolean wasIntentLaunched() { + ThreadCheck.ensureOnUiThread(); + try { + return mNavigationImpl.wasIntentLaunched(); + } catch (RemoteException e) { + throw new APICallException(e); + } + } + + /** + * Whether this navigation resulted in the user deciding whether an external intent should be + * launched (e.g., via a dialog). Returns false if this navigation did not resolve to such a + * user decision, or if that status is not yet known for this navigation. This status is + * determined for a navigation when processing final (post redirect) HTTP response headers. This + * means the only time the embedder can know this status definitively is in + * NavigationCallback.onNavigationFailed. + * + * @since 89 + */ + public boolean isUserDecidingIntentLaunch() { + ThreadCheck.ensureOnUiThread(); + try { + return mNavigationImpl.isUserDecidingIntentLaunch(); + } catch (RemoteException e) { + throw new APICallException(e); + } + } + + /** * Whether this navigation was stopped before it could complete because * NavigationController.stop() was called. *