Commit 85beea0a authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Web Payment] Simple Android payment app factory.

Before this patch, the Android payment apps installed on Chrome OS would
not be available in Web Payment.

This patch queries the list of installed Android payment apps and
returns all of them to Web Payment, if
chrome://flags/#enable-web-payments-experimental-features is enabled.

After this patch, the Android payment apps installed on Chrome OS are
available in Web Payment.

Bug: 1061503
Change-Id: Ifb11741377a0a21166d77c547dbbad21b6daffeb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2302269
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798488}
parent 211b5b7b
......@@ -7,6 +7,7 @@ source_set("browsertests") {
sources = [
"abort_payment_handler_browsertest.cc",
"android_payment_app_factory_browsertest.cc",
"colocated_payment_manifests_browsertest.cc",
"empty_parameters_browsertest.cc",
"has_enrolled_instrument_browsertest.cc",
......
// Copyright 2020 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 "base/test/scoped_feature_list.h"
#include "chrome/test/payments/payment_request_platform_browsertest_base.h"
#include "components/payments/core/features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace payments {
namespace {
class AndroidPaymentAppFactoryTest
: public PaymentRequestPlatformBrowserTestBase {
public:
AndroidPaymentAppFactoryTest() {
feature_list_.InitAndEnableFeature(features::kAppStoreBilling);
}
~AndroidPaymentAppFactoryTest() override = default;
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(AndroidPaymentAppFactoryTest, SmokeTest) {
NavigateTo("a.com", "/app_store_billing_tests/index.html");
ASSERT_EQ("success", content::EvalJs(GetActiveWebContents(),
content::JsReplace(
"addSupportedMethod($1)",
"https://play.google.com/billing")));
ASSERT_EQ("success",
content::EvalJs(GetActiveWebContents(), "createPaymentRequest()"));
ASSERT_EQ("false",
content::EvalJs(GetActiveWebContents(), "canMakePayment()"));
}
} // namespace
} // namespace payments
......@@ -157,6 +157,7 @@ source_set("unit_tests") {
sources = [
"android_app_communication_test_support.h",
"android_app_communication_unittest.cc",
"android_payment_app_factory_unittest.cc",
"android_payment_app_unittest.cc",
"payment_method_manifest_table_unittest.cc",
"service_worker_payment_app_finder_unittest.cc",
......
......@@ -4,12 +4,28 @@
#include "components/payments/content/android_payment_app_factory.h"
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "base/supports_user_data.h"
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/android_payment_app.h"
#include "components/payments/content/payment_request_spec.h"
#include "components/payments/core/android_app_description.h"
#include "components/payments/core/android_app_description_tools.h"
#include "components/payments/core/method_strings.h"
#include "components/payments/core/native_error_strings.h"
#include "components/payments/core/payment_request_data_util.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_document_host_user_data.h"
#include "content/public/browser/web_contents.h"
namespace payments {
......@@ -34,17 +50,69 @@ class AppFinder : public base::SupportsUserData::Data {
AppFinder(const AppFinder& other) = delete;
AppFinder& operator=(const AppFinder& other) = delete;
void FindApps(base::WeakPtr<PaymentAppFactory::Delegate> delegate) {
void FindApps(base::WeakPtr<AndroidAppCommunication> communication,
base::WeakPtr<PaymentAppFactory::Delegate> delegate) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(nullptr, delegate_.get());
DCHECK_NE(nullptr, delegate.get());
DCHECK_EQ(nullptr, communication_.get());
DCHECK_NE(nullptr, communication.get());
DCHECK(delegate->GetSpec()->details().id.has_value());
delegate_ = delegate;
communication_ = communication;
OnDoneCreatingPaymentApps();
communication_->GetAppDescriptions(
delegate_->GetTwaPackageName(),
base::BindOnce(&AppFinder::OnGetAppDescriptions,
weak_ptr_factory_.GetWeakPtr()));
}
private:
void OnGetAppDescriptions(
const base::Optional<std::string>& error_message,
std::vector<std::unique_ptr<AndroidAppDescription>> app_descriptions) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// The browser could be shutting down.
if (!communication_ || !delegate_)
return;
if (error_message.has_value()) {
delegate_->OnPaymentAppCreationError(error_message.value());
OnDoneCreatingPaymentApps();
return;
}
std::vector<std::unique_ptr<AndroidAppDescription>> single_activity_apps;
for (size_t i = 0; i < app_descriptions.size(); ++i) {
auto app = std::move(app_descriptions[i]);
SplitPotentiallyMultipleActivities(std::move(app), &single_activity_apps);
}
for (size_t i = 0; i < single_activity_apps.size(); ++i) {
auto app = std::move(single_activity_apps[i]);
const std::string& default_method =
app->activities.front()->default_payment_method;
DCHECK_EQ(methods::kGooglePlayBilling, default_method);
std::set<std::string> supported_payment_methods = {default_method};
delegate_->OnPaymentAppCreated(std::make_unique<AndroidPaymentApp>(
base::STLSetIntersection<std::set<std::string>>(
delegate_->GetSpec()->payment_method_identifiers_set(),
supported_payment_methods),
data_util::FilterStringifiedMethodData(
delegate_->GetSpec()->stringified_method_data(),
supported_payment_methods),
delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(),
delegate_->GetSpec()->details().id.value(), std::move(app),
communication_));
}
OnDoneCreatingPaymentApps();
}
void OnDoneCreatingPaymentApps() {
if (delegate_)
delegate_->OnDoneCreatingPaymentApps();
......@@ -54,20 +122,25 @@ class AppFinder : public base::SupportsUserData::Data {
base::SupportsUserData* owner_;
base::WeakPtr<PaymentAppFactory::Delegate> delegate_;
base::WeakPtr<AndroidAppCommunication> communication_;
base::WeakPtrFactory<AppFinder> weak_ptr_factory_{this};
};
} // namespace
AndroidPaymentAppFactory::AndroidPaymentAppFactory()
: PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP) {}
AndroidPaymentAppFactory::AndroidPaymentAppFactory(
base::WeakPtr<AndroidAppCommunication> communication)
: PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP),
communication_(communication) {
DCHECK(communication_);
}
AndroidPaymentAppFactory::~AndroidPaymentAppFactory() = default;
void AndroidPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) {
auto app_finder = AppFinder::CreateAndSetOwnedBy(delegate->GetWebContents());
app_finder->FindApps(delegate);
app_finder->FindApps(communication_, delegate);
}
} // namespace payments
......@@ -5,14 +5,20 @@
#ifndef COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_
#define COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_
#include "base/memory/weak_ptr.h"
#include "components/payments/content/payment_app_factory.h"
namespace payments {
class AndroidAppCommunication;
// Retrieves Android payment apps.
class AndroidPaymentAppFactory : public PaymentAppFactory {
public:
AndroidPaymentAppFactory();
// The given |communication| is used for communication with Android payment
// apps.
explicit AndroidPaymentAppFactory(
base::WeakPtr<AndroidAppCommunication> communication);
~AndroidPaymentAppFactory() override;
AndroidPaymentAppFactory(const AndroidPaymentAppFactory& other) = delete;
......@@ -21,6 +27,9 @@ class AndroidPaymentAppFactory : public PaymentAppFactory {
// PaymentAppFactory:
void Create(base::WeakPtr<Delegate> delegate) override;
private:
base::WeakPtr<AndroidAppCommunication> communication_;
};
} // namespace payments
......
......@@ -5,6 +5,7 @@
#include "components/payments/content/payment_app_service.h"
#include "base/feature_list.h"
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/android_payment_app_factory.h"
#include "components/payments/content/autofill_payment_app_factory.h"
#include "components/payments/content/payment_app.h"
......@@ -15,7 +16,7 @@
namespace payments {
PaymentAppService::PaymentAppService() {
PaymentAppService::PaymentAppService(content::BrowserContext* context) {
factories_.emplace_back(std::make_unique<AutofillPaymentAppFactory>());
if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
......@@ -27,7 +28,8 @@ PaymentAppService::PaymentAppService() {
// apps. (Currently it works only on Chrome OS with app store billing payment
// methods.)
if (PaymentsExperimentalFeatures::IsEnabled(features::kAppStoreBilling)) {
factories_.emplace_back(std::make_unique<AndroidPaymentAppFactory>());
factories_.emplace_back(std::make_unique<AndroidPaymentAppFactory>(
AndroidAppCommunication::GetForBrowserContext(context)));
}
}
......
......@@ -14,12 +14,17 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/payments/content/payment_app_factory.h"
namespace content {
class BrowserContext;
} // namespace content
namespace payments {
// Retrieves payment apps of all types.
class PaymentAppService : public KeyedService {
public:
PaymentAppService();
// The |context| pointer is not being saved.
explicit PaymentAppService(content::BrowserContext* context);
~PaymentAppService() override;
// Returns the number of payment app factories, which is the number of times
......
......@@ -43,7 +43,7 @@ PaymentAppServiceFactory::~PaymentAppServiceFactory() = default;
KeyedService* PaymentAppServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new PaymentAppService();
return new PaymentAppService(context);
}
content::BrowserContext* PaymentAppServiceFactory::GetBrowserContextToUse(
......
......@@ -78,7 +78,7 @@ class PaymentRequestStateTest : public testing::Test,
std::move(options), std::move(details), std::move(method_data),
/*observer=*/nullptr, "en-US");
PaymentAppServiceFactory::SetForTesting(
std::make_unique<PaymentAppService>());
std::make_unique<PaymentAppService>(/*context=*/nullptr));
state_ = std::make_unique<PaymentRequestState>(
/*web_contents=*/nullptr,
/*render_frame_host=*/nullptr, GURL("https://example.com"),
......
......@@ -69,6 +69,21 @@ function createPaymentRequest() { // eslint-disable-line no-unused-vars
return 'success';
}
/**
* Check whether payments can be made.
* @return {string} - "true", "false", or an error message.
*/
async function canMakePayment() { // eslint-disable-line no-unused-vars
info('canMakePayment');
try {
const result = await request.canMakePayment();
return (result ? 'true' : 'false');
} catch (e) {
info('canMakePayment error: ' + e.toString());
return e.toString();
}
}
/**
* Show the payment sheet.
* @return {string} - a message indicating whether the operation is successful.
......
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