1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
6 
7 #include "build/build_config.h"
8 #include "chrome/browser/themes/theme_service.h"
9 #include "chrome/browser/themes/theme_service_factory.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/views/frame/browser_view.h"
12 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
13 #include "chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.h"
14 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
15 #include "chrome/browser/web_applications/components/web_application_info.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "content/public/test/browser_test.h"
18 #include "ui/gfx/color_utils.h"
19 #include "ui/views/test/test_views.h"
20 
21 // Tests web-app windows that use the OpaqueBrowserFrameView implementation
22 // for their non client frames.
23 class WebAppOpaqueBrowserFrameViewTest : public InProcessBrowserTest {
24  public:
25   WebAppOpaqueBrowserFrameViewTest() = default;
26   ~WebAppOpaqueBrowserFrameViewTest() override = default;
27 
GetAppURL()28   static GURL GetAppURL() { return GURL("https://test.org"); }
29 
SetUpOnMainThread()30   void SetUpOnMainThread() override { SetThemeMode(ThemeMode::kDefault); }
31 
InstallAndLaunchWebApp(base::Optional<SkColor> theme_color=base::nullopt)32   bool InstallAndLaunchWebApp(
33       base::Optional<SkColor> theme_color = base::nullopt) {
34     auto web_app_info = std::make_unique<WebApplicationInfo>();
35     web_app_info->start_url = GetAppURL();
36     web_app_info->scope = GetAppURL().GetWithoutFilename();
37     web_app_info->theme_color = theme_color;
38 
39     web_app::AppId app_id =
40         web_app::InstallWebApp(browser()->profile(), std::move(web_app_info));
41     Browser* app_browser =
42         web_app::LaunchWebAppBrowser(browser()->profile(), app_id);
43 
44     views::NonClientFrameView* frame_view =
45         BrowserView::GetBrowserViewForBrowser(app_browser)
46             ->GetWidget()
47             ->non_client_view()
48             ->frame_view();
49 
50     // Not all platform configurations use OpaqueBrowserFrameView for their
51     // browser windows, see |CreateBrowserNonClientFrameView()|.
52     bool is_opaque_browser_frame_view =
53         frame_view->GetClassName() == OpaqueBrowserFrameView::kClassName;
54 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
55     DCHECK(is_opaque_browser_frame_view);
56 #else
57     if (!is_opaque_browser_frame_view)
58       return false;
59 #endif
60 
61     opaque_browser_frame_view_ =
62         static_cast<OpaqueBrowserFrameView*>(frame_view);
63     web_app_frame_toolbar_ =
64         opaque_browser_frame_view_->web_app_frame_toolbar_for_testing();
65     DCHECK(web_app_frame_toolbar_);
66     DCHECK(web_app_frame_toolbar_->GetVisible());
67 
68     return true;
69   }
70 
GetRestoredTitleBarHeight()71   int GetRestoredTitleBarHeight() {
72     return opaque_browser_frame_view_->layout()->NonClientTopHeight(true);
73   }
74 
75   enum class ThemeMode {
76     kSystem,
77     kDefault,
78   };
79 
SetThemeMode(ThemeMode theme_mode)80   void SetThemeMode(ThemeMode theme_mode) {
81     ThemeService* theme_service =
82         ThemeServiceFactory::GetForProfile(browser()->profile());
83     if (theme_mode == ThemeMode::kSystem)
84       theme_service->UseSystemTheme();
85     else
86       theme_service->UseDefaultTheme();
87     ASSERT_EQ(theme_service->UsingDefaultTheme(),
88               theme_mode == ThemeMode::kDefault);
89   }
90 
91   OpaqueBrowserFrameView* opaque_browser_frame_view_ = nullptr;
92   WebAppFrameToolbarView* web_app_frame_toolbar_ = nullptr;
93 
94  private:
95   DISALLOW_COPY_AND_ASSIGN(WebAppOpaqueBrowserFrameViewTest);
96 };
97 
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,NoThemeColor)98 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, NoThemeColor) {
99   if (!InstallAndLaunchWebApp())
100     return;
101   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(),
102             gfx::kGoogleGrey900);
103 }
104 
105 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
106 // The app theme color should be ignored in system theme mode.
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,SystemThemeColor)107 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, SystemThemeColor) {
108   SetThemeMode(ThemeMode::kSystem);
109 
110   // Read unthemed native frame color.
111   SkColor native_frame_color =
112       BrowserView::GetBrowserViewForBrowser(browser())
113           ->frame()
114           ->GetFrameView()
115           ->GetFrameColor(BrowserFrameActiveState::kActive);
116   SkColor expected_caption_color =
117       color_utils::GetColorWithMaxContrast(native_frame_color);
118 
119   // Install web app with theme color contrasting against native frame color.
120   SkColor theme_color =
121       color_utils::GetColorWithMaxContrast(native_frame_color);
122   EXPECT_NE(color_utils::IsDark(theme_color),
123             color_utils::IsDark(native_frame_color));
124   ASSERT_TRUE(InstallAndLaunchWebApp(theme_color));
125 
126   // App theme color should be ignored in favor of native system theme.
127   EXPECT_EQ(opaque_browser_frame_view_->GetFrameColor(
128                 BrowserFrameActiveState::kActive),
129             native_frame_color);
130   EXPECT_EQ(opaque_browser_frame_view_->GetCaptionColor(
131                 BrowserFrameActiveState::kActive),
132             expected_caption_color);
133   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(),
134             expected_caption_color);
135 }
136 #endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
137 
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,LightThemeColor)138 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, LightThemeColor) {
139   if (!InstallAndLaunchWebApp(SK_ColorYELLOW))
140     return;
141   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(),
142             gfx::kGoogleGrey900);
143 }
144 
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,DarkThemeColor)145 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, DarkThemeColor) {
146   if (!InstallAndLaunchWebApp(SK_ColorBLUE))
147     return;
148   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(), SK_ColorWHITE);
149 }
150 
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,MediumThemeColor)151 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, MediumThemeColor) {
152   // Use the theme color for Gmail.
153   if (!InstallAndLaunchWebApp(SkColorSetRGB(0xd6, 0x49, 0x3b)))
154     return;
155   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(), SK_ColorWHITE);
156 }
157 
IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest,StaticTitleBarHeight)158 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, StaticTitleBarHeight) {
159   if (!InstallAndLaunchWebApp())
160     return;
161 
162   opaque_browser_frame_view_->Layout();
163   const int title_bar_height = GetRestoredTitleBarHeight();
164   EXPECT_GT(title_bar_height, 0);
165 
166   // Add taller children to the web app frame toolbar RHS.
167   const int container_height = web_app_frame_toolbar_->height();
168   web_app_frame_toolbar_->GetRightContainerForTesting()->AddChildView(
169       new views::StaticSizedView(gfx::Size(1, title_bar_height * 2)));
170   opaque_browser_frame_view_->Layout();
171 
172   // The height of the web app frame toolbar and title bar should not be
173   // affected.
174   EXPECT_EQ(container_height, web_app_frame_toolbar_->height());
175   EXPECT_EQ(title_bar_height, GetRestoredTitleBarHeight());
176 }
177