Commit c86407b2 authored by Eric Willigers's avatar Eric Willigers Committed by Commit Bot

Web Share: Retire desktop implementation

BUG=936687

Change-Id: I716ba65f524ad81a18ddfc372f3694b72b17495d
Reviewed-on: https://chromium-review.googlesource.com/c/1493334Reviewed-by: default avatarSam McNally <sammc@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Eric Willigers <ericwilligers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636332}
parent 73af1629
......@@ -1727,8 +1727,6 @@
'web_share': {
'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/webshare/'\
'|chrome/android/javatests/src/org/chromium/chrome/browser/WebShare.*'\
'|chrome/browser/ui/views/webshare/'\
'|chrome/browser/webshare/'\
'|third_party/blink/web_tests/webshare/'\
'|third_party/blink/web_tests/external/wpt/web-share/'\
'|third_party/blink/public/platform/modules/webshare/'\
......
......@@ -1745,10 +1745,6 @@ jumbo_split_static_library("browser") {
"webauthn/chrome_authenticator_request_delegate.h",
"webauthn/observable_authenticator_list.cc",
"webauthn/observable_authenticator_list.h",
"webshare/share_target_pref_helper.cc",
"webshare/share_target_pref_helper.h",
"webshare/webshare_target.cc",
"webshare/webshare_target.h",
"win/app_icon.cc",
"win/app_icon.h",
"win/automation_controller.cc",
......@@ -3686,8 +3682,6 @@ jumbo_split_static_library("browser") {
sources += [
"renderer_context_menu/spelling_options_submenu_observer.cc",
"renderer_context_menu/spelling_options_submenu_observer.h",
"webshare/share_service_impl.cc",
"webshare/share_service_impl.h",
]
}
......
......@@ -452,10 +452,6 @@
#include "components/services/patch/public/interfaces/constants.mojom.h"
#endif
#if defined(OS_LINUX) || defined(OS_WIN)
#include "chrome/browser/webshare/share_service_impl.h"
#endif
#if defined(OS_WIN) || defined(OS_MACOSX) || \
(defined(OS_LINUX) && !defined(OS_CHROMEOS))
#include "chrome/browser/browser_switcher/browser_switcher_navigation_throttle.h"
......@@ -4447,8 +4443,6 @@ void ChromeContentBrowserClient::InitWebContextInterfaces() {
#if defined(OS_ANDROID)
frame_interfaces_parameterized_->AddInterface(base::Bind(
&ForwardToJavaWebContentsRegistry<blink::mojom::ShareService>));
#elif defined(OS_LINUX) || defined(OS_WIN)
frame_interfaces_->AddInterface(base::Bind(&ShareServiceImpl::Create));
#endif
#if !defined(OS_ANDROID)
......
......@@ -38,7 +38,6 @@
#include "chrome/browser/web_applications/components/web_app_icon_downloader.h"
#include "chrome/browser/web_applications/components/web_app_install_utils.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
#include "chrome/browser/webshare/share_target_pref_helper.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
#include "chrome/common/extensions/extension_constants.h"
......@@ -327,14 +326,6 @@ void BookmarkAppHelper::OnDidPerformInstallableCheck(
web_app::UpdateWebAppInfoFromManifest(*data.manifest, &web_app_info_,
for_installable_site_);
// TODO(mgiuca): Web Share Target should have its own flag, rather than using
// the experimental-web-platform-features flag. https://crbug.com/736178.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kEnableExperimentalWebPlatformFeatures)) {
UpdateShareTargetInPrefs(data.manifest_url, *data.manifest,
profile_->GetPrefs());
}
const std::vector<GURL> web_app_info_icon_urls =
web_app::GetValidIconUrlsToDownload(data, web_app_info_);
......
......@@ -2863,8 +2863,6 @@ jumbo_split_static_library("ui") {
"views/webauthn/hover_list_view.h",
"views/webauthn/sheet_view_factory.cc",
"views/webauthn/sheet_view_factory.h",
"views/webshare/webshare_target_picker_view.cc",
"views/webshare/webshare_target_picker_view.h",
"views_mode_controller.cc",
"views_mode_controller.h",
"webauthn/authenticator_request_sheet_model.h",
......
file://third_party/blink/public/platform/modules/webshare/OWNERS
// 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.
#include "chrome/browser/ui/views/webshare/webshare_target_picker_view.h"
#include <utility>
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/generated_resources.h"
#include "components/constrained_window/constrained_window_views.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/table_model.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/table/table_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/window/dialog_client_view.h"
namespace {
int kWebShareTargetPickerDialogWidth = 500;
int kWebShareTargetPickerDialogHeight = 400;
}
// Supplies data to the table view.
class TargetPickerTableModel : public ui::TableModel {
public:
explicit TargetPickerTableModel(const std::vector<WebShareTarget>& targets);
private:
// ui::TableModel overrides:
int RowCount() override;
base::string16 GetText(int row, int column_id) override;
void SetObserver(ui::TableModelObserver* observer) override;
// Owned by WebShareTargetPickerView.
const std::vector<WebShareTarget>& targets_;
DISALLOW_COPY_AND_ASSIGN(TargetPickerTableModel);
};
TargetPickerTableModel::TargetPickerTableModel(
const std::vector<WebShareTarget>& targets)
: targets_(targets) {}
int TargetPickerTableModel::RowCount() {
return targets_.size();
}
base::string16 TargetPickerTableModel::GetText(int row, int /*column_id*/) {
// Show "title (origin)", to disambiguate titles that are the same, and as a
// security measure.
return l10n_util::GetStringFUTF16(
IDS_WEBSHARE_TARGET_DIALOG_ITEM_TEXT,
base::UTF8ToUTF16(targets_[row].name()),
base::UTF8ToUTF16(targets_[row].manifest_url().GetOrigin().spec()));
}
void TargetPickerTableModel::SetObserver(ui::TableModelObserver* observer) {}
namespace chrome {
void ShowWebShareTargetPickerDialog(
gfx::NativeWindow parent_window,
std::vector<WebShareTarget> targets,
chrome::WebShareTargetPickerCallback callback) {
constrained_window::CreateBrowserModalDialogViews(
new WebShareTargetPickerView(std::move(targets), std::move(callback)),
parent_window)
->Show();
}
} // namespace chrome
WebShareTargetPickerView::WebShareTargetPickerView(
std::vector<WebShareTarget> targets,
chrome::WebShareTargetPickerCallback close_callback)
: targets_(std::move(targets)),
table_model_(std::make_unique<TargetPickerTableModel>(targets_)),
close_callback_(std::move(close_callback)) {
const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
views::BoxLayout* layout =
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical,
provider->GetDialogInsetsForContentType(views::TEXT, views::CONTROL),
provider->GetDistanceMetric(
views::DISTANCE_RELATED_CONTROL_VERTICAL)));
views::Label* overview_label = new views::Label(
l10n_util::GetStringUTF16(IDS_WEBSHARE_TARGET_PICKER_LABEL));
AddChildView(overview_label);
std::vector<ui::TableColumn> table_columns{ui::TableColumn()};
table_ = new views::TableView(table_model_.get(), table_columns,
views::TEXT_ONLY, true);
// Select the first row.
if (targets_.size() > 0)
table_->Select(0);
table_->set_observer(this);
// Create the table parent (a ScrollView which includes the scroll bars and
// border). We add this parent (not the table itself) to the dialog.
views::View* table_parent = table_->CreateParentIfNecessary();
AddChildView(table_parent);
// Make the table expand to fill the space.
layout->SetFlexForView(table_parent, 1);
chrome::RecordDialogCreation(
chrome::DialogIdentifier::WEB_SHARE_TARGET_PICKER);
}
WebShareTargetPickerView::~WebShareTargetPickerView() {
// Clear the pointer from |table_| which currently points at |table_model_|.
// Otherwise, |table_model_| will be deleted before |table_|, and |table_|'s
// destructor will try to call a method on the model.
table_->SetModel(nullptr);
}
gfx::Size WebShareTargetPickerView::CalculatePreferredSize() const {
return gfx::Size(kWebShareTargetPickerDialogWidth,
kWebShareTargetPickerDialogHeight);
}
ui::ModalType WebShareTargetPickerView::GetModalType() const {
return ui::MODAL_TYPE_WINDOW;
}
base::string16 WebShareTargetPickerView::GetWindowTitle() const {
return l10n_util::GetStringUTF16(IDS_WEBSHARE_TARGET_PICKER_TITLE);
}
bool WebShareTargetPickerView::Cancel() {
if (!close_callback_.is_null())
std::move(close_callback_).Run(nullptr);
return true;
}
bool WebShareTargetPickerView::Accept() {
if (!close_callback_.is_null()) {
DCHECK(!table_->selection_model().empty());
std::move(close_callback_).Run(&targets_[table_->FirstSelectedRow()]);
}
return true;
}
base::string16 WebShareTargetPickerView::GetDialogButtonLabel(
ui::DialogButton button) const {
if (button == ui::DIALOG_BUTTON_OK)
return l10n_util::GetStringUTF16(IDS_WEBSHARE_TARGET_PICKER_COMMIT);
return views::DialogDelegateView::GetDialogButtonLabel(button);
}
bool WebShareTargetPickerView::IsDialogButtonEnabled(
ui::DialogButton button) const {
// User shouldn't select OK button if they haven't selected a target.
if (button == ui::DIALOG_BUTTON_OK)
return !table_->selection_model().empty();
return true;
}
void WebShareTargetPickerView::OnSelectionChanged() {
DialogModelChanged();
}
void WebShareTargetPickerView::OnDoubleClick() {
GetDialogClientView()->AcceptWindow();
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_WEBSHARE_WEBSHARE_TARGET_PICKER_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_WEBSHARE_WEBSHARE_TARGET_PICKER_VIEW_H_
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/webshare/webshare_target.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/table/table_view_observer.h"
#include "ui/views/window/dialog_delegate.h"
class TargetPickerTableModel;
class WebShareTargetPickerViewTest;
namespace views {
class TableView;
}
// Dialog that presents the user with a list of share target apps. Allows the
// user to pick one target to be opened and have data passed to it.
//
// NOTE: This dialog has *not* been UI-reviewed, and is being used by an
// in-development feature (Web Share) behind a runtime flag. It should not be
// used by any released code until going through UI review.
class WebShareTargetPickerView : public views::DialogDelegateView,
public views::TableViewObserver {
public:
// |targets| is a list of app title and manifest URL pairs that will be shown
// in a list. If the user picks a target, this calls |callback| with the
// manifest URL of the chosen target, or returns null if the user cancelled
// the share.
WebShareTargetPickerView(std::vector<WebShareTarget> targets,
chrome::WebShareTargetPickerCallback close_callback);
~WebShareTargetPickerView() override;
// views::View overrides:
gfx::Size CalculatePreferredSize() const override;
// views::WidgetDelegate overrides:
ui::ModalType GetModalType() const override;
base::string16 GetWindowTitle() const override;
// views::DialogDelegate overrides:
bool Cancel() override;
bool Accept() override;
base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
bool IsDialogButtonEnabled(ui::DialogButton button) const override;
// views::TableViewObserver overrides:
void OnSelectionChanged() override;
void OnDoubleClick() override;
private:
// For access to |table_|.
friend class WebShareTargetPickerViewTest;
views::TableView* table_ = nullptr;
const std::vector<WebShareTarget> targets_;
std::unique_ptr<TargetPickerTableModel> table_model_;
chrome::WebShareTargetPickerCallback close_callback_;
DISALLOW_COPY_AND_ASSIGN(WebShareTargetPickerView);
};
#endif // CHROME_BROWSER_UI_VIEWS_WEBSHARE_WEBSHARE_TARGET_PICKER_VIEW_H_
// 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.
#include "chrome/browser/ui/views/webshare/webshare_target_picker_view.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/chrome_constrained_window_views_client.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "components/constrained_window/constrained_window_views.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/controls/table/table_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_client_view.h"
#include "ui/views/window/dialog_delegate.h"
#include "url/gurl.h"
constexpr char kAppName1[] = "App One";
constexpr char kAppName2[] = "App Two";
constexpr char kAction[] = "share";
constexpr char kMethod[] = "GET";
constexpr char kEnctype[] = "application/x-www-form-urlencoded";
constexpr char kParamText[] = "text";
constexpr char kParamTitle[] = "title";
constexpr char kParamUrl[] = "url";
constexpr char kUrl1[] = "https://appone.com/path/bits";
constexpr char kUrl2[] = "https://apptwo.xyz";
class WebShareTargetPickerViewTest : public ChromeViewsTestBase {
public:
WebShareTargetPickerViewTest() {}
void SetUp() override {
ChromeViewsTestBase::SetUp();
SetConstrainedWindowViewsClient(CreateChromeConstrainedWindowViewsClient());
// Create the parent widget.
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
parent_widget_.reset(new views::Widget());
parent_widget_->Init(params);
parent_widget_->Show();
}
void TearDown() override {
if (view_)
view_->GetWidget()->CloseNow();
parent_widget_->CloseNow();
quit_closure_ = base::Closure();
constrained_window::SetConstrainedWindowViewsClient(nullptr);
ChromeViewsTestBase::TearDown();
}
protected:
// Creates the WebShareTargetPickerView (available as view()).
void CreateView(std::vector<WebShareTarget> targets) {
view_ = new WebShareTargetPickerView(
std::move(targets),
base::BindOnce(&WebShareTargetPickerViewTest::OnCallback,
base::Unretained(this)));
constrained_window::CreateBrowserModalDialogViews(
view_, parent_widget_->GetNativeWindow())
->Show();
}
// Sets the closure that will be called when the dialog is closed. This is
// used in tests to quit the RunLoop.
void SetQuitClosure(base::Closure&& quit_closure) {
quit_closure_ = std::move(quit_closure);
}
// The view under test.
WebShareTargetPickerView* view() { return view_; }
// The table inside the view (for inspection).
views::TableView* table() { return view_->table_; }
// The result that was returned to the dialog's callback.
const WebShareTarget* result() { return result_; }
private:
void OnCallback(const WebShareTarget* result) {
result_ = result;
if (quit_closure_)
quit_closure_.Run();
}
std::unique_ptr<views::Widget> parent_widget_;
WebShareTargetPickerView* view_ = nullptr;
const WebShareTarget* result_;
base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(WebShareTargetPickerViewTest);
};
// Table with 0 targets. Choose to cancel.
TEST_F(WebShareTargetPickerViewTest, EmptyListCancel) {
CreateView(std::vector<WebShareTarget>());
EXPECT_EQ(0, table()->RowCount());
EXPECT_EQ(-1, table()->FirstSelectedRow()); // Nothing selected.
EXPECT_FALSE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
view()->Cancel();
run_loop.Run();
EXPECT_EQ(nullptr, result());
}
// Table with 2 targets. Choose second target and share.
TEST_F(WebShareTargetPickerViewTest, ChooseItem) {
{
std::vector<WebShareTarget> targets;
std::vector<WebShareTargetFiles> files1;
std::vector<WebShareTargetFiles> files2;
targets.emplace_back(GURL(kUrl1), kAppName1, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl,
std::move(files1));
targets.emplace_back(GURL(kUrl2), kAppName2, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl,
std::move(files2));
CreateView(std::move(targets));
}
EXPECT_EQ(2, table()->RowCount());
EXPECT_EQ(base::ASCIIToUTF16("App One (https://appone.com/)"),
table()->model()->GetText(0, 0));
EXPECT_EQ(base::ASCIIToUTF16("App Two (https://apptwo.xyz/)"),
table()->model()->GetText(1, 0));
EXPECT_EQ(0, table()->FirstSelectedRow());
EXPECT_TRUE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Deselect and ensure OK button is disabled.
table()->Select(-1);
EXPECT_FALSE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
// Select the second app and ensure the OK button is enabled.
table()->Select(1);
EXPECT_TRUE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
view()->Accept();
run_loop.Run();
EXPECT_EQ(WebShareTarget(GURL(kUrl2), kAppName2, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl, {}),
*result());
}
// Table with 1 target. Select using double-click.
TEST_F(WebShareTargetPickerViewTest, ChooseItemWithDoubleClick) {
{
std::vector<WebShareTarget> targets;
std::vector<WebShareTargetFiles> files;
targets.emplace_back(GURL(kUrl1), kAppName1, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl,
std::move(files));
CreateView(std::move(targets));
}
EXPECT_EQ(1, table()->RowCount());
EXPECT_EQ(base::ASCIIToUTF16("App One (https://appone.com/)"),
table()->model()->GetText(0, 0));
EXPECT_EQ(0, table()->FirstSelectedRow());
EXPECT_TRUE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
view()->OnDoubleClick();
run_loop.Run();
EXPECT_EQ(WebShareTarget(GURL(kUrl1), kAppName1, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl, {}),
*result());
}
// Table with 1 target. Select, share and GetText.
TEST_F(WebShareTargetPickerViewTest, GetTextAfterAccept) {
{
std::vector<WebShareTarget> targets;
std::vector<WebShareTargetFiles> files;
targets.emplace_back(GURL(kUrl1), kAppName1, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl,
std::move(files));
CreateView(std::move(targets));
}
EXPECT_EQ(1, table()->RowCount());
EXPECT_EQ(base::ASCIIToUTF16("App One (https://appone.com/)"),
table()->model()->GetText(0, 0));
EXPECT_EQ(0, table()->FirstSelectedRow());
EXPECT_TRUE(view()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
base::RunLoop run_loop;
SetQuitClosure(run_loop.QuitClosure());
view()->Accept();
run_loop.Run();
EXPECT_EQ(base::ASCIIToUTF16("App One (https://appone.com/)"),
table()->model()->GetText(0, 0));
EXPECT_EQ(WebShareTarget(GURL(kUrl1), kAppName1, GURL(kAction), kMethod,
kEnctype, kParamText, kParamTitle, kParamUrl, {}),
*result());
}
file://third_party/blink/public/platform/modules/webshare/OWNERS
// Copyright 2016 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/webshare/share_service_impl.h"
#include <algorithm>
#include <functional>
#include <map>
#include <utility>
#include "base/bind.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/webshare/webshare_target.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/escape.h"
ShareServiceImpl::ShareServiceImpl() : weak_factory_(this) {}
ShareServiceImpl::~ShareServiceImpl() = default;
// static
void ShareServiceImpl::Create(blink::mojom::ShareServiceRequest request) {
mojo::MakeStrongBinding(std::make_unique<ShareServiceImpl>(),
std::move(request));
}
void ShareServiceImpl::ShowPickerDialog(
std::vector<WebShareTarget> targets,
chrome::WebShareTargetPickerCallback callback) {
// TODO(mgiuca): Get the browser window as |parent_window|.
chrome::ShowWebShareTargetPickerDialog(
nullptr /* parent_window */, std::move(targets), std::move(callback));
}
Browser* ShareServiceImpl::GetBrowser() {
return BrowserList::GetInstance()->GetLastActive();
}
void ShareServiceImpl::OpenTargetURL(const GURL& target_url) {
Browser* browser = GetBrowser();
chrome::AddTabAt(browser, target_url,
browser->tab_strip_model()->active_index() + 1, true);
}
PrefService* ShareServiceImpl::GetPrefService() {
return GetBrowser()->profile()->GetPrefs();
}
blink::mojom::EngagementLevel ShareServiceImpl::GetEngagementLevel(
const GURL& url) {
SiteEngagementService* site_engagement_service =
SiteEngagementService::Get(GetBrowser()->profile());
return site_engagement_service->GetEngagementLevel(url);
}
std::vector<WebShareTarget>
ShareServiceImpl::GetTargetsWithSufficientEngagement() {
constexpr blink::mojom::EngagementLevel kMinimumEngagementLevel =
blink::mojom::EngagementLevel::LOW;
PrefService* pref_service = GetPrefService();
const base::DictionaryValue* share_targets_dict =
pref_service->GetDictionary(prefs::kWebShareVisitedTargets);
std::vector<WebShareTarget> sufficiently_engaged_targets;
sufficiently_engaged_targets.reserve(share_targets_dict->size());
for (const auto& it : *share_targets_dict) {
GURL manifest_url(it.first);
// This should not happen, but if the prefs file is corrupted, it might, so
// don't (D)CHECK, just continue gracefully.
if (!manifest_url.is_valid())
continue;
if (GetEngagementLevel(manifest_url) < kMinimumEngagementLevel)
continue;
const base::DictionaryValue* share_target_dict;
bool result = it.second->GetAsDictionary(&share_target_dict);
DCHECK(result);
std::string name;
share_target_dict->GetString("name", &name);
std::string action;
share_target_dict->GetString("action", &action);
std::string method;
share_target_dict->GetString("method", &method);
std::string enctype;
share_target_dict->GetString("enctype", &enctype);
std::string text;
share_target_dict->GetString("text", &text);
std::string title;
share_target_dict->GetString("title", &title);
std::string url;
share_target_dict->GetString("url", &url);
std::vector<WebShareTargetFiles> files;
const base::ListValue* files_list = nullptr;
share_target_dict->GetList("files", &files_list);
if (files_list) {
files.reserve(files_list->GetSize());
for (const base::Value& entry : files_list->GetList()) {
const base::DictionaryValue* file_dict;
entry.GetAsDictionary(&file_dict);
// This should not happen, but if the prefs file is corrupted, it might,
// so don't (D)CHECK, just continue gracefully.
if (!file_dict)
continue;
std::string entry_name;
file_dict->GetString("name", &entry_name);
if (entry_name.empty())
continue;
std::vector<std::string> accept;
const base::ListValue* accept_list = nullptr;
file_dict->GetList("accept", &accept_list);
if (accept_list) {
accept.reserve(accept_list->GetSize());
for (const base::Value& accept_string : accept_list->GetList()) {
accept.push_back(accept_string.GetString());
}
}
files.emplace_back(std::move(entry_name), std::move(accept));
}
}
sufficiently_engaged_targets.emplace_back(
std::move(manifest_url), std::move(name), GURL(std::move(action)),
std::move(method), std::move(enctype), std::move(text),
std::move(title), std::move(url), std::move(files));
}
return sufficiently_engaged_targets;
}
void ShareServiceImpl::Share(const std::string& title,
const std::string& text,
const GURL& share_url,
ShareCallback callback) {
std::vector<WebShareTarget> sufficiently_engaged_targets =
GetTargetsWithSufficientEngagement();
ShowPickerDialog(std::move(sufficiently_engaged_targets),
base::BindOnce(&ShareServiceImpl::OnPickerClosed,
weak_factory_.GetWeakPtr(), title, text,
share_url, std::move(callback)));
}
void ShareServiceImpl::OnPickerClosed(const std::string& title,
const std::string& text,
const GURL& share_url,
ShareCallback callback,
const WebShareTarget* result) {
if (result == nullptr) {
std::move(callback).Run(blink::mojom::ShareError::CANCELED);
return;
}
std::vector<std::pair<std::string, std::string>> entry_list;
if (!result->title().empty() && !title.empty())
entry_list.push_back({result->title(), title});
if (!result->text().empty() && !text.empty())
entry_list.push_back({result->text(), text});
if (!result->url().empty() && share_url.is_valid())
entry_list.push_back({result->url(), share_url.spec()});
auto build_query_part =
[](const std::pair<std::string, std::string>& name_value) {
return base::StringPrintf(
"%s=%s", net::EscapeQueryParamValue(name_value.first, true).c_str(),
net::EscapeQueryParamValue(name_value.second, true).c_str());
};
std::vector<std::string> query_parts;
std::transform(entry_list.begin(), entry_list.end(),
std::back_inserter(query_parts), build_query_part);
std::string query = base::JoinString(query_parts, "&");
url::Replacements<char> replacements;
replacements.SetQuery(query.c_str(), url::Component(0, query.length()));
GURL url = result->action().ReplaceComponents(replacements);
// User should not be able to cause an invalid target URL. The replaced pieces
// are escaped. If somehow we slip through this DCHECK, it will just open
// about:blank.
DCHECK(url.is_valid());
OpenTargetURL(url);
std::move(callback).Run(blink::mojom::ShareError::OK);
}
// Copyright 2016 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_WEBSHARE_SHARE_SERVICE_IMPL_H_
#define CHROME_BROWSER_WEBSHARE_SHARE_SERVICE_IMPL_H_
#include <memory>
#include <string>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "third_party/blink/public/platform/modules/webshare/webshare.mojom.h"
#include "third_party/blink/public/platform/site_engagement.mojom.h"
namespace base {
class DictionaryValue;
} // namespace base
class GURL;
class WebShareTarget;
// Desktop implementation of the ShareService Mojo service.
class ShareServiceImpl : public blink::mojom::ShareService {
public:
ShareServiceImpl();
~ShareServiceImpl() override;
static void Create(mojo::InterfaceRequest<ShareService> request);
// blink::mojom::ShareService overrides:
void Share(const std::string& title,
const std::string& text,
const GURL& share_url,
ShareCallback callback) override;
private:
Browser* GetBrowser();
// Returns the URL template of the target identified by |target_url|
std::string GetTargetTemplate(const std::string& target_url,
const base::DictionaryValue& share_targets);
// Virtual for testing purposes.
virtual PrefService* GetPrefService();
// Returns the site engagement level of the site, |url|, with the user.
// Virtual for testing purposes.
virtual blink::mojom::EngagementLevel GetEngagementLevel(const GURL& url);
// Shows the share picker dialog with |targets| as the list of applications
// presented to the user. Passes the result to |callback|. If the user picks a
// target, the result passed to |callback| is the manifest URL of the chosen
// target, or is null if the user cancelled the share. Virtual for testing.
virtual void ShowPickerDialog(std::vector<WebShareTarget> targets,
chrome::WebShareTargetPickerCallback callback);
// Opens a new tab and navigates to |target_url|.
// Virtual for testing purposes.
virtual void OpenTargetURL(const GURL& target_url);
// Returns all stored Share Targets that have a high enough engagement score
// with the user.
std::vector<WebShareTarget> GetTargetsWithSufficientEngagement();
void OnPickerClosed(const std::string& title,
const std::string& text,
const GURL& share_url,
ShareCallback callback,
const WebShareTarget* result);
base::WeakPtrFactory<ShareServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ShareServiceImpl);
};
#endif // CHROME_BROWSER_WEBSHARE_SHARE_SERVICE_IMPL_H_
This diff is collapsed.
// 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.
#include "chrome/browser/webshare/share_target_pref_helper.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "net/base/escape.h"
void UpdateShareTargetInPrefs(const GURL& manifest_url,
const blink::Manifest& manifest,
PrefService* pref_service) {
DictionaryPrefUpdate update(pref_service, prefs::kWebShareVisitedTargets);
base::DictionaryValue* share_target_dict = update.Get();
// Manifest does not contain a share_target field, or it does but the
// action is not a valid URL.
if (!manifest.share_target.has_value() ||
!manifest.share_target->action.is_valid()) {
share_target_dict->RemoveWithoutPathExpansion(manifest_url.spec(), nullptr);
return;
}
// TODO(mgiuca): This DCHECK is known to fail due to https://crbug.com/762388.
// Currently, this can only happen if flags are turned on. These cases should
// be fixed before this feature is rolled out.
DCHECK(manifest_url.is_valid());
constexpr char kNameKey[] = "name";
constexpr char kActionKey[] = "action";
constexpr char kMethodKey[] = "method";
constexpr char kEnctypeKey[] = "enctype";
constexpr char kTitleKey[] = "title";
constexpr char kTextKey[] = "text";
constexpr char kUrlKey[] = "url";
constexpr char kFilesKey[] = "files";
constexpr char kAcceptKey[] = "accept";
std::unique_ptr<base::DictionaryValue> origin_dict(new base::DictionaryValue);
if (!manifest.name.is_null()) {
origin_dict->SetKey(kNameKey, base::Value(manifest.name.string()));
}
url::Replacements<char> replacements;
replacements.ClearQuery();
origin_dict->SetKey(
kActionKey,
base::Value(manifest.share_target->action.ReplaceComponents(replacements)
.spec()));
origin_dict->SetKey(
kMethodKey,
base::Value(manifest.share_target->method ==
blink::Manifest::ShareTarget::Method::kPost
? "POST"
: "GET"));
origin_dict->SetKey(
kEnctypeKey,
base::Value(manifest.share_target->enctype ==
blink::Manifest::ShareTarget::Enctype::kMultipart
? "multipart/form-data"
: "application/x-www-form-urlencoded"));
if (!manifest.share_target->params.text.is_null()) {
origin_dict->SetKey(
kTextKey, base::Value(manifest.share_target->params.text.string()));
}
if (!manifest.share_target->params.title.is_null()) {
origin_dict->SetKey(
kTitleKey, base::Value(manifest.share_target->params.title.string()));
}
if (!manifest.share_target->params.url.is_null()) {
origin_dict->SetKey(
kUrlKey, base::Value(manifest.share_target->params.url.string()));
}
if (!manifest.share_target->params.files.empty()) {
std::vector<base::Value> files;
files.reserve(manifest.share_target->params.files.size());
for (const blink::Manifest::ShareTargetFile& share_target_file :
manifest.share_target->params.files) {
std::vector<base::Value> accept;
accept.reserve(share_target_file.accept.size());
for (const base::string16& entry : share_target_file.accept) {
accept.push_back(base::Value(entry));
}
files.push_back(base::DictionaryValue());
base::DictionaryValue& file_dict =
static_cast<base::DictionaryValue&>(files.back());
file_dict.SetKey(kNameKey, base::Value(share_target_file.name));
file_dict.SetKey(kAcceptKey, base::ListValue(std::move(accept)));
}
origin_dict->SetKey(kFilesKey, base::Value(files));
}
share_target_dict->SetWithoutPathExpansion(manifest_url.spec(),
std::move(origin_dict));
}
// 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.
#ifndef CHROME_BROWSER_WEBSHARE_SHARE_TARGET_PREF_HELPER_H_
#define CHROME_BROWSER_WEBSHARE_SHARE_TARGET_PREF_HELPER_H_
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "third_party/blink/public/common/manifest/manifest.h"
class GURL;
class PrefService;
// Adds the Web Share target defined by |manifest_url| to |pref_service| under
// kWebShareVisitedTargets. It maps the key |manifest_url| to a dictionary that
// contains a dictionary of the attributes of the share_target field, as well as
// the name field in |manifest|. If the |manifest| doesn't contain a
// share_target field, or it does but there is no url_template field, this will
// remove |manifest_url| from kWebShareVisitedTargets, if it is there.
void UpdateShareTargetInPrefs(const GURL& manifest_url,
const blink::Manifest& manifest,
PrefService* pref_service);
#endif // CHROME_BROWSER_WEBSHARE_SHARE_TARGET_PREF_HELPER_H_
// 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.
#include "chrome/browser/webshare/webshare_target.h"
#include <string>
#include <utility>
#include "base/strings/utf_string_conversions.h"
WebShareTargetFiles::WebShareTargetFiles() {}
WebShareTargetFiles::WebShareTargetFiles(const std::string& name,
const std::vector<std::string>& accept)
: name_(name), accept_(accept) {}
WebShareTargetFiles::~WebShareTargetFiles() {}
WebShareTargetFiles::WebShareTargetFiles(WebShareTargetFiles&& other) = default;
bool WebShareTargetFiles::operator==(const WebShareTargetFiles& other) const {
return std::tie(name_, accept_) == std::tie(other.name_, other.accept_);
}
WebShareTarget::WebShareTarget(const GURL& manifest_url,
const std::string& name,
const GURL& action,
const std::string& method,
const std::string& enctype,
const std::string& text,
const std::string& title,
const std::string& url,
std::vector<WebShareTargetFiles> files)
: manifest_url_(manifest_url),
name_(name),
action_(action),
method_(method),
enctype_(enctype),
text_(text),
title_(title),
url_(url),
files_(std::move(files)) {}
WebShareTarget::~WebShareTarget() {}
WebShareTarget::WebShareTarget(WebShareTarget&& other) = default;
bool WebShareTarget::operator==(const WebShareTarget& other) const {
return std::tie(manifest_url_, name_, action_, method_, enctype_, text_,
title_, url_, files_) ==
std::tie(other.manifest_url_, other.name_, other.action_,
other.method_, other.enctype_, other.text_, other.title_,
other.url_, other.files_);
}
std::ostream& operator<<(std::ostream& out, const WebShareTargetFiles& files) {
out << "WebShareTargetFiles(" << files.name() << ", [";
for (const std::string& accept : files.accept()) {
out << accept << ", ";
}
return out << "])";
}
std::ostream& operator<<(std::ostream& out, const WebShareTarget& target) {
out << "WebShareTarget(GURL(" << target.manifest_url().spec() << "), "
<< target.name() << ", " << target.action() << ", " << target.method()
<< ", " << target.enctype() << ", " << target.text() << ", "
<< target.title() << ", " << target.url() << ", [";
for (const WebShareTargetFiles& files : target.files()) {
out << files << ", ";
}
return out << "])";
}
// 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.
#ifndef CHROME_BROWSER_WEBSHARE_WEBSHARE_TARGET_H_
#define CHROME_BROWSER_WEBSHARE_WEBSHARE_TARGET_H_
#include <string>
#include <vector>
#include "url/gurl.h"
// Represents a ShareTargetFiles entry of a Web Share Target. The attributes are
// usually retrieved from share_target.params.files in the site's manifest.
// https://wicg.github.io/web-share-target/level-2/#sharetargetfiles-and-its-members
class WebShareTargetFiles {
public:
WebShareTargetFiles();
WebShareTargetFiles(const std::string& name,
const std::vector<std::string>& accept);
~WebShareTargetFiles();
// Move constructor
WebShareTargetFiles(WebShareTargetFiles&& other);
// Move assignment
WebShareTargetFiles& operator=(WebShareTargetFiles&& other) = default;
const std::string& name() const { return name_; }
const std::vector<std::string>& accept() const { return accept_; }
bool operator==(const WebShareTargetFiles& other) const;
private:
std::string name_;
std::vector<std::string> accept_;
DISALLOW_COPY_AND_ASSIGN(WebShareTargetFiles);
};
// Used by gtest to print a readable output on test failures.
std::ostream& operator<<(std::ostream& out, const WebShareTargetFiles& target);
// Represents a Web Share Target and its attributes. The attributes are usually
// retrieved from the share_target field in the site's manifest.
// https://wicg.github.io/web-share-target/level-2/#sharetarget-and-its-members
// https://wicg.github.io/web-share-target/level-2/#sharetargetparams-and-its-members
class WebShareTarget {
public:
WebShareTarget(const GURL& manifest_url,
const std::string& name,
const GURL& action,
const std::string& method,
const std::string& enctype,
const std::string& text,
const std::string& title,
const std::string& url,
std::vector<WebShareTargetFiles> files);
~WebShareTarget();
// Move constructor
WebShareTarget(WebShareTarget&& other);
// Move assignment
WebShareTarget& operator=(WebShareTarget&& other) = default;
const std::string& name() const { return name_; }
const GURL& manifest_url() const { return manifest_url_; }
// The action URL to append query parameters to.
const GURL& action() const { return action_; }
const std::string& method() const { return method_; }
const std::string& enctype() const { return enctype_; }
// Parameters
const std::string& text() const { return text_; }
const std::string& title() const { return title_; }
const std::string& url() const { return url_; }
const std::vector<WebShareTargetFiles>& files() const { return files_; }
bool operator==(const WebShareTarget& other) const;
private:
GURL manifest_url_;
std::string name_;
GURL action_;
std::string method_;
std::string enctype_;
std::string text_;
std::string title_;
std::string url_;
std::vector<WebShareTargetFiles> files_;
DISALLOW_COPY_AND_ASSIGN(WebShareTarget);
};
// Used by gtest to print a readable output on test failures.
std::ostream& operator<<(std::ostream& out, const WebShareTarget& target);
#endif // CHROME_BROWSER_WEBSHARE_WEBSHARE_TARGET_H_
......@@ -2929,7 +2929,6 @@ test("unit_tests") {
"../browser/vr/vr_tab_helper_unittest.cc",
"../browser/webauthn/authenticator_request_scheduler_unittest.cc",
"../browser/webauthn/chrome_authenticator_request_delegate_unittest.cc",
"../browser/webshare/share_target_pref_helper_unittest.cc",
"../browser/win/chrome_elf_init_unittest.cc",
"../browser/win/jumplist_file_util_unittest.cc",
"../browser/win/jumplist_update_util_unittest.cc",
......@@ -3637,10 +3636,6 @@ test("unit_tests") {
deps += [ "//components/feature_engagement/test:test_support" ]
}
if (is_linux || is_win) {
sources += [ "../browser/webshare/share_service_impl_unittest.cc" ]
}
if (is_chromeos) {
sources -= [
"../browser/notifications/notification_ui_manager_unittest.cc",
......@@ -4574,7 +4569,6 @@ test("unit_tests") {
"../browser/ui/views/toolbar/toolbar_actions_bar_bubble_views_unittest.cc",
"../browser/ui/views/toolbar/toolbar_button_unittest.cc",
"../browser/ui/views/translate/translate_bubble_view_unittest.cc",
"../browser/ui/views/webshare/webshare_target_picker_view_unittest.cc",
]
if (is_mac) {
sources += [ "../browser/ui/views/frame/browser_non_client_frame_view_mac_unittest.mm" ]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment