blob: 278087675357d556aec11791efa3a58a55d4857b [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include "chromeos/ash/experiences/arc/overlay/arc_overlay_manager.h"
#include "chromeos/ash/experiences/arc/pay/arc_payment_app_bridge.h"
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/android_app_communication_helpers.h"
#include "components/payments/core/android_app_description.h"
#include "components/payments/core/native_error_strings.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
namespace payments {
namespace {
// Invokes the TWA Android app in Android subsystem on Chrome OS.
class AndroidAppCommunicationAsh : public AndroidAppCommunication {
public:
explicit AndroidAppCommunicationAsh(content::BrowserContext* context)
: AndroidAppCommunication(context),
get_app_service_(base::BindRepeating(
&arc::ArcPaymentAppBridge::GetForBrowserContext)) {}
~AndroidAppCommunicationAsh() override = default;
// Disallow copy and assign.
AndroidAppCommunicationAsh(const AndroidAppCommunicationAsh& other) = delete;
AndroidAppCommunicationAsh& operator=(
const AndroidAppCommunicationAsh& other) = delete;
// AndroidAppCommunication implementation:
void GetAppDescriptions(const std::string& twa_package_name,
GetAppDescriptionsCallback callback) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (twa_package_name.empty()) {
// Chrome OS supports Android app payment only through a TWA. An empty
// |twa_package_name| indicates that Chrome was not launched from a TWA,
// so there're no payment apps available.
std::move(callback).Run(/*error_message=*/std::nullopt,
/*app_descriptions=*/{});
return;
}
if (!package_name_for_testing_.empty()) {
std::move(callback).Run(
/*error_message=*/std::nullopt,
CreateAppForTesting(package_name_for_testing_, method_for_testing_));
return;
}
auto* payment_app_service = get_app_service_.Run(context());
if (!payment_app_service) {
std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps,
/*app_descriptions=*/{});
return;
}
payment_app_service->IsPaymentImplemented(
twa_package_name, base::BindOnce(&OnIsImplemented, twa_package_name,
std::move(callback)));
}
// AndroidAppCommunication implementation.
void IsReadyToPay(const std::string& package_name,
const std::string& service_name,
const std::map<std::string, std::set<std::string>>&
stringified_method_data,
const GURL& top_level_origin,
const GURL& payment_request_origin,
const std::string& payment_request_id,
IsReadyToPayCallback callback) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* payment_app_service = get_app_service_.Run(context());
if (!payment_app_service) {
std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps,
/*is_ready_to_pay=*/false);
return;
}
std::optional<std::string> error_message;
auto parameters = CreatePaymentParameters(
package_name, service_name, stringified_method_data, top_level_origin,
payment_request_origin, payment_request_id, &error_message);
if (!parameters) {
std::move(callback).Run(error_message, /*is_ready_to_pay=*/false);
return;
}
payment_app_service->IsReadyToPay(
std::move(parameters),
base::BindOnce(&OnIsReadyToPay, std::move(callback)));
}
// AndroidAppCommunication implementation.
void InvokePaymentApp(
const std::string& package_name,
const std::string& activity_name,
const std::map<std::string, std::set<std::string>>&
stringified_method_data,
const GURL& top_level_origin,
const GURL& payment_request_origin,
const std::string& payment_request_id,
const base::UnguessableToken& request_token,
content::WebContents* web_contents,
const std::optional<base::UnguessableToken>& twa_instance_identifier,
InvokePaymentAppCallback callback) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Create and register a token with ArcOverlayManager for the
// browser window. Doing so is required to allow the Android Play Billing
// interface to be overlaid on top of the browser window.
ash::ArcOverlayManager* const overlay_manager =
ash::ArcOverlayManager::instance();
base::ScopedClosureRunner overlay_state =
overlay_manager->RegisterHostWindow(request_token.ToString(),
web_contents->GetNativeView());
std::optional<std::string> error_message;
if (package_name_for_testing_ == package_name) {
std::move(callback).Run(error_message,
/*is_activity_result_ok=*/true,
method_for_testing_, response_for_testing_);
return;
}
auto* payment_app_service = get_app_service_.Run(context());
if (!payment_app_service) {
std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps,
/*is_activity_result_ok=*/false,
/*payment_method_identifier=*/"",
/*stringified_details=*/kEmptyDictionaryJson);
return;
}
auto parameters = CreatePaymentParameters(
package_name, activity_name, stringified_method_data, top_level_origin,
payment_request_origin, payment_request_id, &error_message);
if (!parameters) {
std::move(callback).Run(error_message,
/*is_activity_result_ok=*/false,
/*payment_method_identifier=*/"",
/*stringified_details=*/kEmptyDictionaryJson);
return;
}
parameters->request_token = request_token.ToString();
payment_app_service->InvokePaymentApp(
std::move(parameters),
base::BindOnce(&OnPaymentAppResponse, std::move(callback),
std::move(overlay_state)));
}
void AbortPaymentApp(const base::UnguessableToken& token,
AbortPaymentAppCallback callback) override {
auto* payment_app_service = get_app_service_.Run(context());
if (!payment_app_service) {
std::move(callback).Run(false);
return;
}
payment_app_service->AbortPaymentApp(token.ToString(), std::move(callback));
}
// AndroidAppCommunication implementation.
void SetForTesting() override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
get_app_service_ = base::BindRepeating(
&arc::ArcPaymentAppBridge::GetForBrowserContextForTesting);
}
// AndroidAppCommunication implementation.
void SetAppForTesting(const std::string& package_name,
const std::string& method,
const std::string& response) override {
package_name_for_testing_ = package_name;
method_for_testing_ = method;
response_for_testing_ = response;
}
private:
std::string package_name_for_testing_;
std::string method_for_testing_;
std::string response_for_testing_;
base::RepeatingCallback<arc::ArcPaymentAppBridge*(content::BrowserContext*)>
get_app_service_;
};
} // namespace
// Declared in cross-platform header file. See:
// //components/payments/content/android_app_communication.h
// static
std::unique_ptr<AndroidAppCommunication> AndroidAppCommunication::Create(
content::BrowserContext* context) {
return std::make_unique<AndroidAppCommunicationAsh>(context);
}
} // namespace payments