blob: 6957530d69df879c35a271e130c7b64279d20e4c [file] [log] [blame]
// Copyright 2017 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 "components/payments/content/payment_app.h"
#include <algorithm>
#include "base/callback.h"
#include "base/containers/contains.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/payments/content/autofill_payment_app.h"
#include "components/payments/core/features.h"
#include "components/payments/core/payments_experimental_features.h"
namespace payments {
namespace {
// Returns the sorting group of a payment app. This is used to order payment
// apps in the order of:
// 1. Built-in 1st-party payment handlers.
// 2. Installed 3rd-party payment handlers
// 3. Complete autofill instruments
// 4. Just-in-time installable payment handlers that is not yet installed.
// 5. Incomplete autofill instruments
int GetSortingGroup(const PaymentApp& app) {
switch (app.type()) {
case PaymentApp::Type::INTERNAL:
return 1;
case PaymentApp::Type::SERVICE_WORKER_APP:
case PaymentApp::Type::NATIVE_MOBILE_APP:
// If the experimental feature is enabled, sort 3rd-party payment handlers
// that needs installation below autofill instruments.
if (app.NeedsInstallation() &&
PaymentsExperimentalFeatures::IsEnabled(
features::kDownRankJustInTimePaymentApp)) {
return 4;
}
return 2;
case PaymentApp::Type::AUTOFILL:
if (app.IsCompleteForPayment()) {
return 3;
}
return 5;
case PaymentApp::Type::UNDEFINED:
NOTREACHED();
return 99;
}
}
} // namespace
PaymentApp::PaymentApp(int icon_resource_id, Type type)
: icon_resource_id_(icon_resource_id), type_(type) {}
PaymentApp::~PaymentApp() {}
const SkBitmap* PaymentApp::icon_bitmap() const {
return nullptr;
}
std::string PaymentApp::GetApplicationIdentifierToHide() const {
return std::string();
}
std::set<std::string> PaymentApp::GetApplicationIdentifiersThatHideThisApp()
const {
return std::set<std::string>();
}
void PaymentApp::IsValidForPaymentMethodIdentifier(
const std::string& payment_method_identifier,
bool* is_valid) const {
*is_valid = base::Contains(app_method_names_, payment_method_identifier);
}
const std::set<std::string>& PaymentApp::GetAppMethodNames() const {
return app_method_names_;
}
ukm::SourceId PaymentApp::UkmSourceId() {
return ukm::kInvalidSourceId;
}
bool PaymentApp::IsWaitingForPaymentDetailsUpdate() const {
return false;
}
void PaymentApp::AbortPaymentApp(
base::OnceCallback<void(bool)> abort_callback) {
std::move(abort_callback).Run(/*aborted=*/false);
}
bool PaymentApp::IsPreferred() const {
return false;
}
mojom::PaymentResponsePtr PaymentApp::SetAppSpecificResponseFields(
mojom::PaymentResponsePtr response) const {
return response;
}
// static
void PaymentApp::SortApps(std::vector<std::unique_ptr<PaymentApp>>* apps) {
DCHECK(apps);
std::sort(apps->begin(), apps->end(),
[](const std::unique_ptr<PaymentApp>& lhs,
const std::unique_ptr<PaymentApp>& rhs) { return *lhs < *rhs; });
}
// static
void PaymentApp::SortApps(std::vector<PaymentApp*>* apps) {
DCHECK(apps);
std::sort(
apps->begin(), apps->end(),
[](const PaymentApp* lhs, const PaymentApp* rhs) { return *lhs < *rhs; });
}
bool PaymentApp::operator<(const PaymentApp& other) const {
int sorting_group = GetSortingGroup(*this);
int other_sorting_group = GetSortingGroup(other);
// First sort payment apps by their sorting group.
if (sorting_group != other_sorting_group) {
return sorting_group < other_sorting_group;
}
// Within a group, compare by completeness.
// Non-autofill apps have max completeness score. Autofill cards are sorted
// based on completeness. (Each autofill card is considered an app.)
int completeness = GetCompletenessScore() - other.GetCompletenessScore();
if (completeness != 0)
return completeness > 0;
// Sort autofill cards using their frecency scores as tie breaker.
if (type_ == Type::AUTOFILL) {
DCHECK_EQ(other.type(), Type::AUTOFILL);
return static_cast<const AutofillPaymentApp*>(this)
->credit_card()
->HasGreaterFrecencyThan(
static_cast<const AutofillPaymentApp*>(&other)->credit_card(),
autofill::AutofillClock::Now());
}
// SW based payment apps are sorted based on whether they will handle shipping
// delegation or not (i.e. shipping address is requested and the app supports
// the delegation.).
if (HandlesShippingAddress() != other.HandlesShippingAddress())
return HandlesShippingAddress();
// SW based payment apps are sorted based on the number of the contact field
// delegations that they will handle (i.e. number of contact fields which are
// requested and the apps support their delegations.)
int supported_contact_delegations_num = 0;
if (HandlesPayerEmail())
supported_contact_delegations_num++;
if (HandlesPayerName())
supported_contact_delegations_num++;
if (HandlesPayerPhone())
supported_contact_delegations_num++;
int other_supported_contact_delegations_num = 0;
if (other.HandlesPayerEmail())
other_supported_contact_delegations_num++;
if (other.HandlesPayerName())
other_supported_contact_delegations_num++;
if (other.HandlesPayerPhone())
other_supported_contact_delegations_num++;
int contact_delegations_diff = supported_contact_delegations_num -
other_supported_contact_delegations_num;
if (contact_delegations_diff != 0)
return contact_delegations_diff > 0;
// SW based payment apps are sorted based on whether they can be pre-selected
// or not. Note that autofill cards are already sorted by CanPreselect() since
// they are sorted by completeness and type matching.
if (CanPreselect() != other.CanPreselect())
return CanPreselect();
return false;
}
} // namespace payments