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") { ...@@ -7,6 +7,7 @@ source_set("browsertests") {
sources = [ sources = [
"abort_payment_handler_browsertest.cc", "abort_payment_handler_browsertest.cc",
"android_payment_app_factory_browsertest.cc",
"colocated_payment_manifests_browsertest.cc", "colocated_payment_manifests_browsertest.cc",
"empty_parameters_browsertest.cc", "empty_parameters_browsertest.cc",
"has_enrolled_instrument_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") { ...@@ -157,6 +157,7 @@ source_set("unit_tests") {
sources = [ sources = [
"android_app_communication_test_support.h", "android_app_communication_test_support.h",
"android_app_communication_unittest.cc", "android_app_communication_unittest.cc",
"android_payment_app_factory_unittest.cc",
"android_payment_app_unittest.cc", "android_payment_app_unittest.cc",
"payment_method_manifest_table_unittest.cc", "payment_method_manifest_table_unittest.cc",
"service_worker_payment_app_finder_unittest.cc", "service_worker_payment_app_finder_unittest.cc",
......
...@@ -4,12 +4,28 @@ ...@@ -4,12 +4,28 @@
#include "components/payments/content/android_payment_app_factory.h" #include "components/payments/content/android_payment_app_factory.h"
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility> #include <utility>
#include <vector>
#include "base/bind.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/stl_util.h"
#include "base/supports_user_data.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_context.h"
#include "content/public/browser/browser_thread.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" #include "content/public/browser/web_contents.h"
namespace payments { namespace payments {
...@@ -34,17 +50,69 @@ class AppFinder : public base::SupportsUserData::Data { ...@@ -34,17 +50,69 @@ class AppFinder : public base::SupportsUserData::Data {
AppFinder(const AppFinder& other) = delete; AppFinder(const AppFinder& other) = delete;
AppFinder& operator=(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_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_EQ(nullptr, delegate_.get()); DCHECK_EQ(nullptr, delegate_.get());
DCHECK_NE(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; delegate_ = delegate;
communication_ = communication;
OnDoneCreatingPaymentApps(); communication_->GetAppDescriptions(
delegate_->GetTwaPackageName(),
base::BindOnce(&AppFinder::OnGetAppDescriptions,
weak_ptr_factory_.GetWeakPtr()));
} }
private: 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() { void OnDoneCreatingPaymentApps() {
if (delegate_) if (delegate_)
delegate_->OnDoneCreatingPaymentApps(); delegate_->OnDoneCreatingPaymentApps();
...@@ -54,20 +122,25 @@ class AppFinder : public base::SupportsUserData::Data { ...@@ -54,20 +122,25 @@ class AppFinder : public base::SupportsUserData::Data {
base::SupportsUserData* owner_; base::SupportsUserData* owner_;
base::WeakPtr<PaymentAppFactory::Delegate> delegate_; base::WeakPtr<PaymentAppFactory::Delegate> delegate_;
base::WeakPtr<AndroidAppCommunication> communication_;
base::WeakPtrFactory<AppFinder> weak_ptr_factory_{this}; base::WeakPtrFactory<AppFinder> weak_ptr_factory_{this};
}; };
} // namespace } // namespace
AndroidPaymentAppFactory::AndroidPaymentAppFactory() AndroidPaymentAppFactory::AndroidPaymentAppFactory(
: PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP) {} base::WeakPtr<AndroidAppCommunication> communication)
: PaymentAppFactory(PaymentApp::Type::NATIVE_MOBILE_APP),
communication_(communication) {
DCHECK(communication_);
}
AndroidPaymentAppFactory::~AndroidPaymentAppFactory() = default; AndroidPaymentAppFactory::~AndroidPaymentAppFactory() = default;
void AndroidPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) { void AndroidPaymentAppFactory::Create(base::WeakPtr<Delegate> delegate) {
auto app_finder = AppFinder::CreateAndSetOwnedBy(delegate->GetWebContents()); auto app_finder = AppFinder::CreateAndSetOwnedBy(delegate->GetWebContents());
app_finder->FindApps(delegate); app_finder->FindApps(communication_, delegate);
} }
} // namespace payments } // namespace payments
...@@ -5,14 +5,20 @@ ...@@ -5,14 +5,20 @@
#ifndef COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_ #ifndef COMPONENTS_PAYMENTS_CONTENT_ANDROID_PAYMENT_APP_FACTORY_H_
#define 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" #include "components/payments/content/payment_app_factory.h"
namespace payments { namespace payments {
class AndroidAppCommunication;
// Retrieves Android payment apps. // Retrieves Android payment apps.
class AndroidPaymentAppFactory : public PaymentAppFactory { class AndroidPaymentAppFactory : public PaymentAppFactory {
public: public:
AndroidPaymentAppFactory(); // The given |communication| is used for communication with Android payment
// apps.
explicit AndroidPaymentAppFactory(
base::WeakPtr<AndroidAppCommunication> communication);
~AndroidPaymentAppFactory() override; ~AndroidPaymentAppFactory() override;
AndroidPaymentAppFactory(const AndroidPaymentAppFactory& other) = delete; AndroidPaymentAppFactory(const AndroidPaymentAppFactory& other) = delete;
...@@ -21,6 +27,9 @@ class AndroidPaymentAppFactory : public PaymentAppFactory { ...@@ -21,6 +27,9 @@ class AndroidPaymentAppFactory : public PaymentAppFactory {
// PaymentAppFactory: // PaymentAppFactory:
void Create(base::WeakPtr<Delegate> delegate) override; void Create(base::WeakPtr<Delegate> delegate) override;
private:
base::WeakPtr<AndroidAppCommunication> communication_;
}; };
} // namespace payments } // namespace payments
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "components/payments/content/payment_app_service.h" #include "components/payments/content/payment_app_service.h"
#include "base/feature_list.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/android_payment_app_factory.h"
#include "components/payments/content/autofill_payment_app_factory.h" #include "components/payments/content/autofill_payment_app_factory.h"
#include "components/payments/content/payment_app.h" #include "components/payments/content/payment_app.h"
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
namespace payments { namespace payments {
PaymentAppService::PaymentAppService() { PaymentAppService::PaymentAppService(content::BrowserContext* context) {
factories_.emplace_back(std::make_unique<AutofillPaymentAppFactory>()); factories_.emplace_back(std::make_unique<AutofillPaymentAppFactory>());
if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) { if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
...@@ -27,7 +28,8 @@ PaymentAppService::PaymentAppService() { ...@@ -27,7 +28,8 @@ PaymentAppService::PaymentAppService() {
// apps. (Currently it works only on Chrome OS with app store billing payment // apps. (Currently it works only on Chrome OS with app store billing payment
// methods.) // methods.)
if (PaymentsExperimentalFeatures::IsEnabled(features::kAppStoreBilling)) { 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 @@ ...@@ -14,12 +14,17 @@
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/payments/content/payment_app_factory.h" #include "components/payments/content/payment_app_factory.h"
namespace content {
class BrowserContext;
} // namespace content
namespace payments { namespace payments {
// Retrieves payment apps of all types. // Retrieves payment apps of all types.
class PaymentAppService : public KeyedService { class PaymentAppService : public KeyedService {
public: public:
PaymentAppService(); // The |context| pointer is not being saved.
explicit PaymentAppService(content::BrowserContext* context);
~PaymentAppService() override; ~PaymentAppService() override;
// Returns the number of payment app factories, which is the number of times // Returns the number of payment app factories, which is the number of times
......
...@@ -43,7 +43,7 @@ PaymentAppServiceFactory::~PaymentAppServiceFactory() = default; ...@@ -43,7 +43,7 @@ PaymentAppServiceFactory::~PaymentAppServiceFactory() = default;
KeyedService* PaymentAppServiceFactory::BuildServiceInstanceFor( KeyedService* PaymentAppServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const { content::BrowserContext* context) const {
return new PaymentAppService(); return new PaymentAppService(context);
} }
content::BrowserContext* PaymentAppServiceFactory::GetBrowserContextToUse( content::BrowserContext* PaymentAppServiceFactory::GetBrowserContextToUse(
......
...@@ -78,7 +78,7 @@ class PaymentRequestStateTest : public testing::Test, ...@@ -78,7 +78,7 @@ class PaymentRequestStateTest : public testing::Test,
std::move(options), std::move(details), std::move(method_data), std::move(options), std::move(details), std::move(method_data),
/*observer=*/nullptr, "en-US"); /*observer=*/nullptr, "en-US");
PaymentAppServiceFactory::SetForTesting( PaymentAppServiceFactory::SetForTesting(
std::make_unique<PaymentAppService>()); std::make_unique<PaymentAppService>(/*context=*/nullptr));
state_ = std::make_unique<PaymentRequestState>( state_ = std::make_unique<PaymentRequestState>(
/*web_contents=*/nullptr, /*web_contents=*/nullptr,
/*render_frame_host=*/nullptr, GURL("https://example.com"), /*render_frame_host=*/nullptr, GURL("https://example.com"),
......
...@@ -69,6 +69,21 @@ function createPaymentRequest() { // eslint-disable-line no-unused-vars ...@@ -69,6 +69,21 @@ function createPaymentRequest() { // eslint-disable-line no-unused-vars
return 'success'; 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. * Show the payment sheet.
* @return {string} - a message indicating whether the operation is successful. * @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