| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/payments/content/android_app_communication_helpers.h" |
| |
| #include "chromeos/components/payments/mojom/payment_app.mojom.h" |
| #include "chromeos/components/payments/mojom/payment_app_types.mojom.h" |
| #include "components/payments/core/chrome_os_error_strings.h" |
| #include "components/payments/core/method_strings.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "url/gurl.h" |
| |
| namespace payments { |
| |
| const char kEmptyDictionaryJson[] = "{}"; |
| |
| void OnIsImplemented( |
| const std::string& twa_package_name, |
| AndroidAppCommunication::GetAppDescriptionsCallback callback, |
| chromeos::payments::mojom::IsPaymentImplementedResultPtr response) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| DCHECK(!twa_package_name.empty()); |
| |
| if (response.is_null()) { |
| std::move(callback).Run(errors::kEmptyResponse, /*app_descriptions=*/{}); |
| return; |
| } |
| |
| if (response->is_error()) { |
| std::move(callback).Run(response->get_error(), /*app_descriptions=*/{}); |
| return; |
| } |
| |
| if (!response->is_valid()) { |
| std::move(callback).Run(errors::kInvalidResponse, /*app_descriptions=*/{}); |
| return; |
| } |
| |
| if (response->get_valid()->activity_names.empty()) { |
| // If a TWA does not implement PAY intent in any of its activities, then |
| // |activity_names| is empty, which is not an error. |
| std::move(callback).Run(/*error_message=*/std::nullopt, |
| /*app_descriptions=*/{}); |
| return; |
| } |
| |
| if (response->get_valid()->activity_names.size() != 1U) { |
| std::move(callback).Run(errors::kMoreThanOneActivity, |
| /*app_descriptions=*/{}); |
| return; |
| } |
| |
| auto activity = std::make_unique<AndroidActivityDescription>(); |
| activity->name = response->get_valid()->activity_names.front(); |
| |
| // The only available payment method identifier in a Chrome OS TWA at this |
| // time. |
| activity->default_payment_method = methods::kGooglePlayBilling; |
| |
| auto app = std::make_unique<AndroidAppDescription>(); |
| app->package = twa_package_name; |
| app->activities.emplace_back(std::move(activity)); |
| app->service_names = response->get_valid()->service_names; |
| |
| std::vector<std::unique_ptr<AndroidAppDescription>> app_descriptions; |
| app_descriptions.emplace_back(std::move(app)); |
| |
| std::move(callback).Run(/*error_message=*/std::nullopt, |
| std::move(app_descriptions)); |
| } |
| |
| void OnIsReadyToPay(AndroidAppCommunication::IsReadyToPayCallback callback, |
| chromeos::payments::mojom::IsReadyToPayResultPtr response) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| if (response.is_null()) { |
| std::move(callback).Run(errors::kEmptyResponse, /*is_ready_to_pay=*/false); |
| return; |
| } |
| |
| if (response->is_error()) { |
| std::move(callback).Run(response->get_error(), /*is_ready_to_pay=*/false); |
| return; |
| } |
| |
| if (!response->is_response()) { |
| std::move(callback).Run(errors::kInvalidResponse, |
| /*is_ready_to_pay=*/false); |
| return; |
| } |
| |
| std::move(callback).Run(/*error_message=*/std::nullopt, |
| response->get_response()); |
| } |
| |
| void OnPaymentAppResponse( |
| AndroidAppCommunication::InvokePaymentAppCallback callback, |
| base::ScopedClosureRunner overlay_state, |
| chromeos::payments::mojom::InvokePaymentAppResultPtr response) { |
| if (overlay_state) { |
| // Dismiss and prevent any further overlays |
| overlay_state.RunAndReset(); |
| } |
| |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (response.is_null()) { |
| std::move(callback).Run(errors::kEmptyResponse, |
| /*is_activity_result_ok=*/false, |
| /*payment_method_identifier=*/"", |
| /*stringified_details=*/kEmptyDictionaryJson); |
| return; |
| } |
| |
| if (response->is_error()) { |
| std::move(callback).Run(response->get_error(), |
| /*is_activity_result_ok=*/false, |
| /*payment_method_identifier=*/"", |
| /*stringified_details=*/kEmptyDictionaryJson); |
| return; |
| } |
| |
| if (!response->is_valid()) { |
| std::move(callback).Run(errors::kInvalidResponse, |
| /*is_activity_result_ok=*/false, |
| /*payment_method_identifier=*/"", |
| /*stringified_details=*/kEmptyDictionaryJson); |
| return; |
| } |
| |
| // Chrome OS TWA currently supports only methods::kGooglePlayBilling payment |
| // method identifier. |
| std::move(callback).Run( |
| /*error_message=*/std::nullopt, |
| response->get_valid()->is_activity_result_ok, |
| /*payment_method_identifier=*/methods::kGooglePlayBilling, |
| response->get_valid()->stringified_details); |
| } |
| |
| chromeos::payments::mojom::PaymentParametersPtr CreatePaymentParameters( |
| const std::string& package_name, |
| const std::string& activity_or_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, |
| std::optional<std::string>* error_message) { |
| // Chrome OS TWA supports only kGooglePlayBilling payment method identifier |
| // at this time. |
| auto supported_method_iterator = |
| stringified_method_data.find(methods::kGooglePlayBilling); |
| if (supported_method_iterator == stringified_method_data.end()) { |
| return nullptr; |
| } |
| |
| // Chrome OS TWA supports only one set of payment method specific data. |
| if (supported_method_iterator->second.size() > 1) { |
| *error_message = errors::kMoreThanOneMethodData; |
| return nullptr; |
| } |
| |
| auto parameters = chromeos::payments::mojom::PaymentParameters::New(); |
| parameters->stringified_method_data = |
| supported_method_iterator->second.empty() |
| ? kEmptyDictionaryJson |
| : *supported_method_iterator->second.begin(); |
| parameters->package_name = package_name; |
| parameters->activity_or_service_name = activity_or_service_name; |
| parameters->top_level_origin = top_level_origin.spec(); |
| parameters->payment_request_origin = payment_request_origin.spec(); |
| parameters->payment_request_id = payment_request_id; |
| |
| return parameters; |
| } |
| |
| std::vector<std::unique_ptr<AndroidAppDescription>> CreateAppForTesting( |
| const std::string& package_name, |
| const std::string& method_name) { |
| auto activity = std::make_unique<AndroidActivityDescription>(); |
| activity->name = package_name + ".Activity"; |
| activity->default_payment_method = method_name; |
| auto app = std::make_unique<AndroidAppDescription>(); |
| app->package = package_name; |
| app->activities.emplace_back(std::move(activity)); |
| std::vector<std::unique_ptr<AndroidAppDescription>> app_descriptions; |
| app_descriptions.emplace_back(std::move(app)); |
| return app_descriptions; |
| } |
| |
| } // namespace payments |