[Web Payment][Chrome OS] Android app communication - IsReadyToPay.

This patch adds a cross-platform way for Web Payment feature to query
the IS_READY_TO_PAY intent of an Android app. As a first step, only the
Android apps installed on the Android subsystem of Chrome OS are
supported.

Bug: 1061503
Change-Id: I3055874e96e046a233c5bb223c9e4422d7e8e966
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2248427
Commit-Queue: Rouslan Solomakhin <[email protected]>
Reviewed-by: Liquan (Max) Gu <[email protected]>
Cr-Commit-Position: refs/heads/master@{#797954}
diff --git a/components/payments/content/android_app_communication_unittest.cc b/components/payments/content/android_app_communication_unittest.cc
index 9331f65..29b26e8 100644
--- a/components/payments/content/android_app_communication_unittest.cc
+++ b/components/payments/content/android_app_communication_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/payments/content/android_app_communication_test_support.h"
 #include "components/payments/core/android_app_description.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace payments {
 namespace {
@@ -59,9 +60,16 @@
     apps_ = std::move(apps);
   }
 
+  void OnIsReadyToPayResponse(const base::Optional<std::string>& error,
+                              bool is_ready_to_pay) {
+    error_ = error;
+    is_ready_to_pay_ = is_ready_to_pay;
+  }
+
   std::unique_ptr<AndroidAppCommunicationTestSupport> support_;
   base::Optional<std::string> error_;
   std::vector<std::unique_ptr<AndroidAppDescription>> apps_;
+  bool is_ready_to_pay_ = false;
 };
 
 TEST_F(AndroidAppCommunicationTest, OneInstancePerBrowserContext) {
@@ -250,5 +258,174 @@
   EXPECT_TRUE(apps_.empty());
 }
 
+TEST_F(AndroidAppCommunicationTest, NoArcForIsReadyToPay) {
+  // Intentionally do not set an instance.
+
+  support_->ExpectNoIsReadyToPayQuery();
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data["https://play.google.com/billing"].insert("{}");
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  ASSERT_TRUE(error_.has_value());
+  EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+  EXPECT_FALSE(is_ready_to_pay_);
+}
+
+TEST_F(AndroidAppCommunicationTest, TwaIsReadyToPayOnlyWithPlayBilling) {
+  auto scoped_initialization = support_->CreateScopedInitialization();
+
+  support_->ExpectNoIsReadyToPayQuery();
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data["https://example.com"].insert("{}");
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
+    EXPECT_FALSE(error_.has_value());
+  } else {
+    ASSERT_TRUE(error_.has_value());
+    EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+  }
+
+  EXPECT_FALSE(is_ready_to_pay_);
+}
+
+TEST_F(AndroidAppCommunicationTest, MoreThanOnePaymentMethodDataNotReadyToPay) {
+  auto scoped_initialization = support_->CreateScopedInitialization();
+
+  support_->ExpectNoIsReadyToPayQuery();
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data["https://play.google.com/billing"].insert(
+      "{\"product_id\": \"1\"}");
+  stringified_method_data["https://play.google.com/billing"].insert(
+      "{\"product_id\": \"2\"}");
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  ASSERT_TRUE(error_.has_value());
+
+  if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
+    EXPECT_EQ("At most one payment method specific data is supported.",
+              error_.value());
+  } else {
+    EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+  }
+
+  EXPECT_FALSE(is_ready_to_pay_);
+}
+
+TEST_F(AndroidAppCommunicationTest, EmptyMethodDataIsReadyToPay) {
+  auto scoped_initialization = support_->CreateScopedInitialization();
+
+  support_->ExpectQueryIsReadyToPayAndRespond(true);
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data.insert(std::make_pair(
+      "https://play.google.com/billing", std::set<std::string>()));
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
+    EXPECT_FALSE(error_.has_value());
+    EXPECT_TRUE(is_ready_to_pay_);
+  } else {
+    ASSERT_TRUE(error_.has_value());
+    EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+    EXPECT_FALSE(is_ready_to_pay_);
+  }
+}
+
+TEST_F(AndroidAppCommunicationTest, NotReadyToPay) {
+  auto scoped_initialization = support_->CreateScopedInitialization();
+
+  support_->ExpectQueryIsReadyToPayAndRespond(false);
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data["https://play.google.com/billing"].insert("{}");
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
+    EXPECT_FALSE(error_.has_value());
+  } else {
+    ASSERT_TRUE(error_.has_value());
+    EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+  }
+
+  EXPECT_FALSE(is_ready_to_pay_);
+}
+
+TEST_F(AndroidAppCommunicationTest, ReadyToPay) {
+  auto scoped_initialization = support_->CreateScopedInitialization();
+
+  support_->ExpectQueryIsReadyToPayAndRespond(true);
+
+  auto communication =
+      AndroidAppCommunication::GetForBrowserContext(support_->context());
+  communication->SetForTesting();
+
+  std::map<std::string, std::set<std::string>> stringified_method_data;
+  stringified_method_data["https://play.google.com/billing"].insert("{}");
+  communication->IsReadyToPay(
+      "com.example.app", "com.example.app.Service", stringified_method_data,
+      GURL("https://top-level-origin.com"),
+      GURL("https://payment-request-origin.com"), "payment-request-id",
+      base::BindOnce(&AndroidAppCommunicationTest::OnIsReadyToPayResponse,
+                     base::Unretained(this)));
+
+  if (support_->AreAndroidAppsSupportedOnThisPlatform()) {
+    EXPECT_FALSE(error_.has_value());
+    EXPECT_TRUE(is_ready_to_pay_);
+  } else {
+    ASSERT_TRUE(error_.has_value());
+    EXPECT_EQ("Unable to invoke Android apps.", error_.value());
+    EXPECT_FALSE(is_ready_to_pay_);
+  }
+}
+
 }  // namespace
 }  // namespace payments