chromium/content/browser/display_cutout/display_cutout_browsertest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/browser/display_cutout/display_cutout_constants.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
#include "third_party/blink/public/mojom/page/display_cutout.mojom.h"

namespace content {

namespace {

#if BUILDFLAG(IS_ANDROID)

// These inset and flags simulate when we are not extending into the cutout.
const auto kNoCutoutInsets = gfx::Insets();

// These inset and flags simulate when the we are extending into the cutout.
const auto kCutoutInsets = gfx::Insets::TLBR(1, 0, 1, 0);

// These inset and flags simulate when we are extending into the cutout and have
// rotated the device so that the cutout is on the other sides.
const auto kRotatedCutoutInsets = gfx::Insets::TLBR(0, 1, 0, 1);

#endif

class TestWebContentsObserver : public WebContentsObserver {};

// Used for forcing a specific |blink::mojom::DisplayMode| during a test.
class DisplayCutoutWebContentsDelegate : public WebContentsDelegate {};

const char kTestHTML[] =;

}  // namespace

class DisplayCutoutBrowserTest : public ContentBrowserTest {};

// The viewport meta tag is only enabled on Android.
#if BUILDFLAG(IS_ANDROID)

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, ViewportFit_Fullscreen) {
  LoadTestPageWithViewportFitFromMeta("cover");
  LoadSubFrameWithViewportFitMetaValue("contain");

  {
    TestWebContentsObserver observer(web_contents_impl());
    SimulateFullscreenStateChanged(MainFrame(), true);
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kCover);
    web_contents_impl()->SetDisplayCutoutSafeArea(kCutoutInsets);
  }

  {
    TestWebContentsObserver observer(web_contents_impl());
    SimulateFullscreenStateChanged(ChildFrame(), true);
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kContain);
    web_contents_impl()->SetDisplayCutoutSafeArea(kNoCutoutInsets);
  }

  {
    TestWebContentsObserver observer(web_contents_impl());
    SimulateFullscreenStateChanged(ChildFrame(), false);
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kCover);

    // This simulates the user rotating the device.
    web_contents_impl()->SetDisplayCutoutSafeArea(kCutoutInsets);
    web_contents_impl()->SetDisplayCutoutSafeArea(kRotatedCutoutInsets);
  }

  {
    TestWebContentsObserver observer(web_contents_impl());
    SimulateFullscreenStateChanged(MainFrame(), false);
    SimulateFullscreenExit();
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kAuto);
    web_contents_impl()->SetDisplayCutoutSafeArea(kNoCutoutInsets);
  }

  shell()->Close();
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest,
                       ViewportFit_Fullscreen_Update) {
  LoadTestPageWithViewportFitFromMeta("cover");

  {
    TestWebContentsObserver observer(web_contents_impl());
    SimulateFullscreenStateChanged(MainFrame(), true);
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kCover);
    web_contents_impl()->SetDisplayCutoutSafeArea(kNoCutoutInsets);
  }

  {
    TestWebContentsObserver observer(web_contents_impl());
    ClearViewportFitTag();
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kAuto);
    web_contents_impl()->SetDisplayCutoutSafeArea(kNoCutoutInsets);
  }
  shell()->Close();
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, ViewportFit_Noop_Navigate) {
  {
    TestWebContentsObserver observer(web_contents_impl());
    LoadTestPageWithViewportFitFromMeta("cover");
    EXPECT_FALSE(observer.has_value());
  }
  LoadTestPageWithData("");
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest,
                       ViewportFit_Noop_WebContentsDestroyed) {
  {
    TestWebContentsObserver observer(web_contents_impl());
    LoadTestPageWithViewportFitFromMeta("cover");
    EXPECT_FALSE(observer.has_value());
  }

  shell()->Close();
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, WebDisplayMode) {
  // Inject the custom delegate used for this test.
  std::unique_ptr<DisplayCutoutWebContentsDelegate> delegate(
      new DisplayCutoutWebContentsDelegate());
  web_contents_impl()->SetDelegate(delegate.get());
  EXPECT_EQ(delegate.get(), web_contents_impl()->GetDelegate());

  {
    TestWebContentsObserver observer(web_contents_impl());
    LoadTestPageWithViewportFitFromMeta("cover");
    EXPECT_FALSE(observer.has_value());
  }
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, WebDisplayMode_Fullscreen) {
  // Inject the custom delegate used for this test.
  std::unique_ptr<DisplayCutoutWebContentsDelegate> delegate(
      new DisplayCutoutWebContentsDelegate());
  delegate->SetDisplayMode(blink::mojom::DisplayMode::kFullscreen);
  web_contents_impl()->SetDelegate(delegate.get());
  EXPECT_EQ(delegate.get(), web_contents_impl()->GetDelegate());

  {
    TestWebContentsObserver observer(web_contents_impl());
    LoadTestPageWithViewportFitFromMeta("cover");
    observer.WaitForWantedValue(blink::mojom::ViewportFit::kCover);
  }
}

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, WebDisplayMode_Standalone) {
  // Inject the custom delegate used for this test.
  std::unique_ptr<DisplayCutoutWebContentsDelegate> delegate(
      new DisplayCutoutWebContentsDelegate());
  delegate->SetDisplayMode(blink::mojom::DisplayMode::kStandalone);
  web_contents_impl()->SetDelegate(delegate.get());
  EXPECT_EQ(delegate.get(), web_contents_impl()->GetDelegate());

  {
    TestWebContentsObserver observer(web_contents_impl());
    LoadTestPageWithViewportFitFromMeta("cover");
    EXPECT_FALSE(observer.has_value());
  }
}

#endif

IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserTest, PublishSafeAreaVariables) {}

#if BUILDFLAG(IS_ANDROID)
class DisplayCutoutBrowserWithEdgeToEdgeTest : public DisplayCutoutBrowserTest {
 public:
  DisplayCutoutBrowserWithEdgeToEdgeTest() = default;

  DisplayCutoutBrowserWithEdgeToEdgeTest(
      const DisplayCutoutBrowserWithEdgeToEdgeTest&) = delete;
  DisplayCutoutBrowserWithEdgeToEdgeTest& operator=(
      const DisplayCutoutBrowserWithEdgeToEdgeTest&) = delete;

  void SetUp() override {
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeatures(
        /*enabled_features=*/{features::kDrawCutoutEdgeToEdge},
        /*disabled_features=*/{});

    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());

    embedded_test_server()->ServeFilesFromDirectory(temp_dir_.GetPath());
    ASSERT_TRUE(embedded_test_server()->Start());

    ContentBrowserTest::SetUp();
  }
};

// Sometimes, the fullscreen exit logic is triggered before navigation
// completes, causing a check to the RenderFrameHost before it's been set. This
// ensures that flow doesn't cause a crash.
IN_PROC_BROWSER_TEST_F(DisplayCutoutBrowserWithEdgeToEdgeTest,
                       FullscreenExitBeforeNavigationCompletes) {
  TestWebContentsObserver observer(web_contents_impl());
  SimulateFullscreenExit();
}

#endif

}  //  namespace content