blob: c8d8c95bda85e032c5c6f6de1412336a339b0b10 [file] [log] [blame]
Yining Wang4c6d1e02019-04-10 21:07:011// Copyright 2019 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/manifest_web_app_browser_controller.h"
6
Yining Wang40eae8f2019-05-02 19:04:157#include "chrome/browser/profiles/profile.h"
Yining Wang40eae8f2019-05-02 19:04:158#include "chrome/browser/ssl/security_state_tab_helper.h"
Yining Wang4c6d1e02019-04-10 21:07:019#include "chrome/browser/ui/browser.h"
Evan Stade2229a562021-01-12 18:30:0710#include "components/webapps/browser/installable/installable_manager.h"
Yining Wang4c6d1e02019-04-10 21:07:0111#include "content/public/browser/navigation_entry.h"
Yining Wang40eae8f2019-05-02 19:04:1512#include "content/public/common/url_constants.h"
13#include "extensions/common/constants.h"
Frédéric Wang073e74a2020-12-16 17:43:3214#include "services/network/public/cpp/is_potentially_trustworthy.h"
Dana Fried5876c78d2019-12-25 00:12:2215#include "third_party/blink/public/common/manifest/manifest.h"
Yining Wang4c6d1e02019-04-10 21:07:0116#include "ui/gfx/favicon_size.h"
17#include "ui/gfx/image/image_skia.h"
18#include "url/gurl.h"
19
20ManifestWebAppBrowserController::ManifestWebAppBrowserController(
21 Browser* browser)
Dana Fried5876c78d2019-12-25 00:12:2222 : AppBrowserController(browser, /*app_id=*/base::nullopt) {}
Yining Wang4c6d1e02019-04-10 21:07:0123
24ManifestWebAppBrowserController::~ManifestWebAppBrowserController() = default;
25
Eric Willigers6aadc642019-11-02 00:17:3326bool ManifestWebAppBrowserController::HasMinimalUiButtons() const {
27 return false;
28}
29
Alan Cuttera2cb8d72019-07-28 22:59:1330bool ManifestWebAppBrowserController::ShouldShowCustomTabBar() const {
Yining Wang40eae8f2019-05-02 19:04:1531 content::WebContents* web_contents =
32 browser()->tab_strip_model()->GetActiveWebContents();
33
Alan Cuttera2cb8d72019-07-28 22:59:1334 // Don't show until a navigation has occurred.
Yining Wang40eae8f2019-05-02 19:04:1535 if (!web_contents || web_contents->GetLastCommittedURL().is_empty())
36 return false;
37
Alan Cuttera2cb8d72019-07-28 22:59:1338 // Show if the web_contents is not on a secure origin.
Frédéric Wang073e74a2020-12-16 17:43:3239 if (!network::IsUrlPotentiallyTrustworthy(app_start_url_))
Yining Wang40eae8f2019-05-02 19:04:1540 return true;
Yining Wang40eae8f2019-05-02 19:04:1541
Alan Cuttera2cb8d72019-07-28 22:59:1342 // Show if web_contents is not currently in scope.
Jay Harris4e0a6c72019-07-08 23:29:0143 if (!IsUrlInAppScope(web_contents->GetLastCommittedURL()) ||
44 !IsUrlInAppScope(web_contents->GetVisibleURL())) {
Yining Wang40eae8f2019-05-02 19:04:1545 return true;
46 }
47
Alan Cuttera2cb8d72019-07-28 22:59:1348 // Show if on a insecure external website. This checks the security level,
49 // different from IsOriginSecure which just checks the origin itself.
Evan Stade57f160f2020-12-08 15:59:3750 if (!webapps::InstallableManager::IsContentSecure(web_contents))
Yining Wang40eae8f2019-05-02 19:04:1551 return true;
52
Yining Wang4c6d1e02019-04-10 21:07:0153 return false;
54}
55
Yining Wang4c6d1e02019-04-10 21:07:0156gfx::ImageSkia ManifestWebAppBrowserController::GetWindowAppIcon() const {
57 gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia();
58 if (!page_icon.isNull())
59 return page_icon;
60
61 // The extension icon may be loading still. Return a transparent icon rather
62 // than using a placeholder to avoid flickering.
63 SkBitmap bitmap;
64 bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize);
65 bitmap.eraseColor(SK_ColorTRANSPARENT);
66 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
67}
68
69gfx::ImageSkia ManifestWebAppBrowserController::GetWindowIcon() const {
70 return browser()->GetCurrentPageIcon().AsImageSkia();
71}
72
Mugdha Lakhani23954ef22020-06-25 21:56:2173base::string16 ManifestWebAppBrowserController::GetAppShortName() const {
74 return base::string16();
Yining Wang4c6d1e02019-04-10 21:07:0175}
76
77base::string16 ManifestWebAppBrowserController::GetFormattedUrlOrigin() const {
Alan Cutterc658135b42020-09-28 23:09:5378 return FormatUrlOrigin(GetAppStartUrl());
Yining Wang4c6d1e02019-04-10 21:07:0179}
80
Alan Cutterc658135b42020-09-28 23:09:5381GURL ManifestWebAppBrowserController::GetAppStartUrl() const {
82 return app_start_url_;
Yining Wang40eae8f2019-05-02 19:04:1583}
84
Jay Harris4e0a6c72019-07-08 23:29:0185bool ManifestWebAppBrowserController::IsUrlInAppScope(const GURL& url) const {
Dana Fried5876c78d2019-12-25 00:12:2286 // Prefer to use manifest scope URL if available; fall back to app launch URL
87 // if not available. Manifest fallback is always launch URL minus filename,
88 // query, and fragment.
89 const GURL scope_url = !manifest_scope_.is_empty()
90 ? manifest_scope_
Alan Cutterc658135b42020-09-28 23:09:5391 : GetAppStartUrl().GetWithoutFilename();
Dana Fried5876c78d2019-12-25 00:12:2292
93 return IsInScope(url, scope_url);
Jay Harris4e0a6c72019-07-08 23:29:0194}
95
Yining Wang40eae8f2019-05-02 19:04:1596void ManifestWebAppBrowserController::OnTabInserted(
97 content::WebContents* contents) {
Dana Fried5876c78d2019-12-25 00:12:2298 // Since we are experimenting with multi-tab PWAs, we only try to load the
99 // manifest if this is the first web contents being loaded in this window.
100 DCHECK(!browser()->tab_strip_model()->empty());
101 if (browser()->tab_strip_model()->count() == 1) {
Alan Cutterc658135b42020-09-28 23:09:53102 app_start_url_ = contents->GetURL();
Dana Fried5876c78d2019-12-25 00:12:22103 contents->GetManifest(
104 base::BindOnce(&ManifestWebAppBrowserController::OnManifestLoaded,
105 weak_factory_.GetWeakPtr()));
106 }
Eric Willigers4a5f7a92019-05-10 19:19:26107 AppBrowserController::OnTabInserted(contents);
Alan Cuttera2cb8d72019-07-28 22:59:13108 UpdateCustomTabBarVisibility(false);
Yining Wang4c6d1e02019-04-10 21:07:01109}
Dana Fried5876c78d2019-12-25 00:12:22110
111void ManifestWebAppBrowserController::OnManifestLoaded(
112 const GURL& manifest_url,
113 const blink::Manifest& manifest) {
114 manifest_scope_ = manifest.scope;
115}
116
117// static
118bool ManifestWebAppBrowserController::IsInScope(const GURL& url,
119 const GURL& scope) {
120 if (!url::IsSameOriginWith(scope, url))
121 return false;
122
123 std::string scope_path = scope.path();
124 if (base::EndsWith(scope_path, "/", base::CompareCase::SENSITIVE))
125 scope_path = scope_path.substr(0, scope_path.length() - 1);
126
127 const std::string url_path = url.path();
128 return url_path == scope_path ||
129 base::StartsWith(url_path, scope_path + "/",
130 base::CompareCase::SENSITIVE);
131}