blob: d9214dccb235c492cbca4b1850b5f329e15c6d90 [file] [log] [blame]
// 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/strings/string_util.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 "third_party/blink/public/common/manifest/manifest_share_target_util.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;
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 url_template;
share_target_dict->GetString("url_template", &url_template);
sufficiently_engaged_targets.emplace_back(std::move(manifest_url),
std::move(name),
GURL(std::move(url_template)));
}
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;
}
GURL url_template_filled;
if (!blink::ReplaceWebShareUrlPlaceholders(result->url_template(), title,
text, share_url,
&url_template_filled)) {
// This error should not be possible at share time. content::ManifestParser
// should have filtered out invalid targets at manifest parse time.
std::move(callback).Run(blink::mojom::ShareError::INTERNAL_ERROR);
return;
}
// 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_template_filled.is_valid());
OpenTargetURL(url_template_filled);
std::move(callback).Run(blink::mojom::ShareError::OK);
}