1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "ash/constants/ash_features.h"
#include "base/containers/to_vector.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.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/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h"
#include "chrome/browser/ash/guest_os/guest_os_external_protocol_handler.h"
#include "chrome/browser/chromeos/arc/arc_external_protocol_dialog.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/external_protocol_dialog.h"
#include "chrome/browser/web_applications/app_service/publisher_helper.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
#include "chromeos/constants/chromeos_features.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/gfx/text_elider.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
#include "url/gurl.h"
using content::WebContents;
// The external protocol dialog for Chrome OS shown when we have a URL with a
// Tel scheme but there are no handlers.
class ExternalProtocolNoHandlersTelSchemeDialog : public views::DialogDelegate {
public:
explicit ExternalProtocolNoHandlersTelSchemeDialog(
aura::Window* parent_window)
: creation_time_(base::TimeTicks::Now()) {
DCHECK(parent_window);
SetOwnedByWidget(OwnedByWidgetPassKey());
views::DialogDelegate::SetButtons(
static_cast<int>(ui::mojom::DialogButton::kOk));
views::DialogDelegate::SetButtonLabel(
ui::mojom::DialogButton::kOk,
l10n_util::GetStringUTF16(IDS_EXTERNAL_PROTOCOL_CLOSE_BUTTON_TEXT));
message_box_view_ = new views::MessageBoxView();
message_box_view_->SetMessageWidth(400);
views::DialogDelegate::CreateDialogWidget(this, nullptr, parent_window)
->Show();
}
ExternalProtocolNoHandlersTelSchemeDialog(
const ExternalProtocolNoHandlersTelSchemeDialog&) = delete;
ExternalProtocolNoHandlersTelSchemeDialog& operator=(
const ExternalProtocolNoHandlersTelSchemeDialog&) = delete;
~ExternalProtocolNoHandlersTelSchemeDialog() override = default;
// views::DialogDelegate:
std::u16string GetWindowTitle() const override {
// We display a message to the user on how to use the Click to Call feature.
return l10n_util::GetStringUTF16(
IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_HELP_TEXT_NO_DEVICES);
}
views::View* GetContentsView() override { return message_box_view_; }
const views::Widget* GetWidget() const override {
return message_box_view_->GetWidget();
}
views::Widget* GetWidget() override { return message_box_view_->GetWidget(); }
private:
// The message box view whose commands we handle.
raw_ptr<views::MessageBoxView> message_box_view_;
// The time at which this dialog was created.
base::TimeTicks creation_time_;
};
namespace {
void OnArcHandled(const GURL& url,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document,
base::WeakPtr<WebContents> web_contents,
bool handled) {
if (handled) {
return;
}
// If WebContents have been destroyed, do not show any dialog.
if (!web_contents) {
return;
}
aura::Window* parent_window = web_contents->GetTopLevelNativeWindow();
// If WebContents has been detached from window tree, do not show any dialog.
if (!parent_window || !parent_window->GetRootWindow()) {
return;
}
// Display the standard ExternalProtocolDialog if Guest OS has a handler.
// Otherwise, if there is no handler and the URL is a Tel-link, show the No
// Handler Tel Scheme dialog
std::optional<guest_os::GuestOsUrlHandler> registration =
guest_os::GuestOsUrlHandler::GetForUrl(
Profile::FromBrowserContext(web_contents->GetBrowserContext()), url);
if (registration) {
new ExternalProtocolDialog(web_contents.get(), url,
base::UTF8ToUTF16(registration->name()),
initiating_origin, initiator_document);
} else if (url.scheme() == url::kTelScheme) {
new ExternalProtocolNoHandlersTelSchemeDialog(parent_window);
}
}
std::string GetAppName(apps::AppServiceProxy* proxy,
const std::string& app_id) {
std::optional<std::string> app_name;
proxy->AppRegistryCache().ForOneApp(
app_id,
[&](const apps::AppUpdate& update) { app_name = update.ShortName(); });
CHECK(app_name);
return *app_name;
}
void HandleWebAppManifestProtocolHandler(
Profile* profile,
WebContents* web_contents,
const GURL& url,
const std::vector<std::string>& app_ids,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document) {
CHECK(!app_ids.empty());
CHECK(apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile));
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
if (app_ids.size() > 1) {
// TODO(crbug.com/422422887): Figure out how to disambiguate conflicting
// protocol handlers; for now, pick the first one in the list.
static constexpr std::string_view kConfictingProtocolHandlersWarning =
"There's more than one web application handling %s links : [%s]; "
"ChromeOS currently doesn't support disambiguating multiple handlers.";
if (content::RenderFrameHost* rfh =
initiator_document.AsRenderFrameHostIfValid()) {
std::vector<std::string> app_names = base::ToVector(
app_ids,
[&](const auto& app_id) { return GetAppName(proxy, app_id); });
rfh->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kWarning,
base::StringPrintf(kConfictingProtocolHandlersWarning, url.scheme(),
base::JoinString(app_names, ",")));
}
}
new ExternalProtocolDialog(web_contents, url,
base::UTF8ToUTF16(GetAppName(proxy, app_ids[0])),
initiating_origin, std::move(initiator_document));
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
// ExternalProtocolHandler
// static
void ExternalProtocolHandler::RunExternalProtocolDialog(
const GURL& url,
WebContents* web_contents,
ui::PageTransition page_transition,
bool has_user_gesture,
bool is_in_fenced_frame_tree,
const std::optional<url::Origin>& initiating_origin,
content::WeakDocumentPtr initiator_document,
const std::u16string& program_name) {
// Don't launch anything from Shimless RMA app.
if (ash::features::IsShimlessRMA3pDiagnosticsEnabled() &&
ash::IsShimlessRmaAppBrowserContext(web_contents->GetBrowserContext())) {
return;
}
auto* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (std::vector<std::string> app_ids =
web_app::GetWebAppIdsForProtocolUrl(profile, url);
!app_ids.empty()) {
HandleWebAppManifestProtocolHandler(profile, web_contents, url, app_ids,
initiating_origin, initiator_document);
return;
}
// Check if ARC version of the dialog is available and run ARC
// version when possible.
arc::RunArcExternalProtocolDialog(
url, initiating_origin, web_contents->GetWeakPtr(), page_transition,
has_user_gesture, is_in_fenced_frame_tree,
std::make_unique<arc::ArcIntentHelperMojoAsh>(),
base::BindOnce(&OnArcHandled, url, initiating_origin,
std::move(initiator_document),
web_contents->GetWeakPtr()));
}
|