From 0e23f0666af8a6359ae42bc50ab8be1c0e49d5ba Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Tue, 29 Jun 2021 15:26:28 +0200 Subject: [PATCH 1/4] Added priceCurrencySymbol to SkuDetailsWrapper --- .../in_app_purchase_android/CHANGELOG.md | 4 ++++ .../plugins/inapppurchase/Translator.java | 20 ++++++++++++++++ .../plugins/inapppurchase/TranslatorTest.java | 23 +++++++++++++++++++ .../sku_details_wrapper.dart | 7 ++++++ .../sku_details_wrapper.g.dart | 2 ++ .../in_app_purchase_android/pubspec.yaml | 2 +- .../sku_details_wrapper_test.dart | 1 + 7 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md index 316a67b9ce99..824b432d5021 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4+2 + +* Added price currency symbol to SkuDetailsWrapper. + ## 0.1.4+1 * Fixed typos. diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 079c18ab8b5c..7546fe7db58d 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -13,8 +13,10 @@ import com.android.billingclient.api.SkuDetails; import java.util.ArrayList; import java.util.Collections; +import java.util.Currency; import java.util.HashMap; import java.util.List; +import java.util.Locale; /** Handles serialization of {@link com.android.billingclient.api.BillingClient} related objects. */ /*package*/ class Translator { @@ -30,6 +32,7 @@ static HashMap fromSkuDetail(SkuDetails detail) { info.put("price", detail.getPrice()); info.put("priceAmountMicros", detail.getPriceAmountMicros()); info.put("priceCurrencyCode", detail.getPriceCurrencyCode()); + info.put("priceCurrencySymbol", currencySymbolFromCode(detail.getPriceCurrencyCode())); info.put("sku", detail.getSku()); info.put("type", detail.getType()); info.put("subscriptionPeriod", detail.getSubscriptionPeriod()); @@ -123,4 +126,21 @@ static HashMap fromBillingResult(BillingResult billingResult) { info.put("debugMessage", billingResult.getDebugMessage()); return info; } + + /** + * Gets the symbol of for the given currency code for the default {@link Locale.Category#DISPLAY + * DISPLAY} locale. For example, for the US Dollar, the symbol is "$" if the default locale is the + * US, while for other locales it may be "US$". If no symbol can be determined, the ISO 4217 + * currency code is returned. + * + * @param currencyCode the ISO 4217 code of the currency + * @return the symbol of this currency code for the default {@link Locale.Category#DISPLAY + * DISPLAY} locale + * @exception NullPointerException if currencyCode is null + * @exception IllegalArgumentException if currencyCode is not a supported ISO 4217 + * code. + */ + static String currencySymbolFromCode(String currencyCode) { + return Currency.getInstance(currencyCode).getSymbol(); + } } diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index e65afcf42467..02ce6be27bef 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -7,6 +7,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -22,8 +24,10 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.json.JSONException; +import org.junit.Before; import org.junit.Test; public class TranslatorTest { @@ -32,6 +36,12 @@ public class TranslatorTest { private static final String PURCHASE_EXAMPLE_JSON = "{\"orderId\":\"foo\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\", \"obfuscatedAccountId\":\"Account101\", \"obfuscatedProfileId\": \"Profile105\"}"; + @Before + public void setup() { + Locale locale = new Locale("en", "us"); + Locale.setDefault(locale); + } + @Test public void fromSkuDetail() throws JSONException { final SkuDetails expected = new SkuDetails(SKU_DETAIL_EXAMPLE_JSON); @@ -182,6 +192,18 @@ public void fromBillingResult_debugMessageNull() throws JSONException { assertEquals(billingResultMap.get("debugMessage"), newBillingResult.getDebugMessage()); } + @Test + public void currencyCodeFromSymbol() { + assertEquals("€", Translator.currencySymbolFromCode("EUR")); + assertEquals("$", Translator.currencySymbolFromCode("USD")); + try { + Translator.currencySymbolFromCode("EUROPACOIN"); + fail("Translator should throw an exception"); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + } + } + private void assertSerialized(SkuDetails expected, Map serialized) { assertEquals(expected.getDescription(), serialized.get("description")); assertEquals(expected.getFreeTrialPeriod(), serialized.get("freeTrialPeriod")); @@ -194,6 +216,7 @@ private void assertSerialized(SkuDetails expected, Map serialize assertEquals(expected.getPrice(), serialized.get("price")); assertEquals(expected.getPriceAmountMicros(), serialized.get("priceAmountMicros")); assertEquals(expected.getPriceCurrencyCode(), serialized.get("priceCurrencyCode")); + assertEquals("$", serialized.get("priceCurrencySymbol")); assertEquals(expected.getSku(), serialized.get("sku")); assertEquals(expected.getSubscriptionPeriod(), serialized.get("subscriptionPeriod")); assertEquals(expected.getTitle(), serialized.get("title")); diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.dart index e3d13df2262a..da4d5c73d851 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.dart @@ -38,6 +38,7 @@ class SkuDetailsWrapper { required this.price, required this.priceAmountMicros, required this.priceCurrencyCode, + required this.priceCurrencySymbol, required this.sku, required this.subscriptionPeriod, required this.title, @@ -91,6 +92,12 @@ class SkuDetailsWrapper { @JsonKey(defaultValue: '') final String priceCurrencyCode; + /// [price] localized currency symbol + /// For example, for the US Dollar, the symbol is "$" if the locale + /// is the US, while for other locales it may be "US$". + @JsonKey(defaultValue: '') + final String priceCurrencySymbol; + /// The product ID in Google Play Console. @JsonKey(defaultValue: '') final String sku; diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart index a14affdf9ed3..49e86087bc13 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart @@ -17,6 +17,7 @@ SkuDetailsWrapper _$SkuDetailsWrapperFromJson(Map json) { price: json['price'] as String? ?? '', priceAmountMicros: json['priceAmountMicros'] as int? ?? 0, priceCurrencyCode: json['priceCurrencyCode'] as String? ?? '', + priceCurrencySymbol: json['priceCurrencySymbol'] as String? ?? '', sku: json['sku'] as String? ?? '', subscriptionPeriod: json['subscriptionPeriod'] as String? ?? '', title: json['title'] as String? ?? '', @@ -37,6 +38,7 @@ Map _$SkuDetailsWrapperToJson(SkuDetailsWrapper instance) => 'price': instance.price, 'priceAmountMicros': instance.priceAmountMicros, 'priceCurrencyCode': instance.priceCurrencyCode, + 'priceCurrencySymbol': instance.priceCurrencySymbol, 'sku': instance.sku, 'subscriptionPeriod': instance.subscriptionPeriod, 'title': instance.title, diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml index e0de3411e0ff..efc774aa4f1e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml @@ -2,7 +2,7 @@ name: in_app_purchase_android description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs. repository: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase/in_app_purchase_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 0.1.4+1 +version: 0.1.4+2 environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart index ead6d26576f3..7aece605db33 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -17,6 +17,7 @@ final SkuDetailsWrapper dummySkuDetails = SkuDetailsWrapper( price: 'price', priceAmountMicros: 1000, priceCurrencyCode: 'priceCurrencyCode', + priceCurrencySymbol: r'$', sku: 'sku', subscriptionPeriod: 'subscriptionPeriod', title: 'title', From 5ef69c40991ea2e101231a20567aeca8b262476b Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 8 Jul 2021 13:43:01 +0200 Subject: [PATCH 2/4] remove test of unsupported euro sign --- .../java/io/flutter/plugins/inapppurchase/TranslatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 02ce6be27bef..2837dceea652 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -194,7 +194,6 @@ public void fromBillingResult_debugMessageNull() throws JSONException { @Test public void currencyCodeFromSymbol() { - assertEquals("€", Translator.currencySymbolFromCode("EUR")); assertEquals("$", Translator.currencySymbolFromCode("USD")); try { Translator.currencySymbolFromCode("EUROPACOIN"); From 373f5788fb2be10ad803b53f3f2ec501e205816c Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 8 Jul 2021 15:43:12 +0200 Subject: [PATCH 3/4] Added currencySymbol in the ProductDetails --- .../lib/src/types/google_play_product_details.dart | 3 +++ packages/in_app_purchase/in_app_purchase_android/pubspec.yaml | 2 +- .../test/in_app_purchase_android_platform_test.dart | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_product_details.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_product_details.dart index 62589038804e..59d33fe26223 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_product_details.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/types/google_play_product_details.dart @@ -18,6 +18,7 @@ class GooglePlayProductDetails extends ProductDetails { required double rawPrice, required String currencyCode, required this.skuDetails, + required String currencySymbol, }) : super( id: id, title: title, @@ -25,6 +26,7 @@ class GooglePlayProductDetails extends ProductDetails { price: price, rawPrice: rawPrice, currencyCode: currencyCode, + currencySymbol: currencySymbol, ); /// Points back to the [SkuDetailsWrapper] object that was used to generate @@ -43,6 +45,7 @@ class GooglePlayProductDetails extends ProductDetails { price: skuDetails.price, rawPrice: ((skuDetails.priceAmountMicros) / 1000000.0).toDouble(), currencyCode: skuDetails.priceCurrencyCode, + currencySymbol: skuDetails.priceCurrencySymbol, skuDetails: skuDetails, ); } diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml index efc774aa4f1e..41136e7501f6 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: collection: ^1.15.0 flutter: sdk: flutter - in_app_purchase_platform_interface: ^1.0.0 + in_app_purchase_platform_interface: ^1.1.0 json_annotation: ^4.0.1 meta: ^1.3.0 test: ^1.16.0 diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart index 01c73d6ed43e..52ec08bea07a 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart @@ -108,6 +108,7 @@ void main() { expect(response.productDetails.first.description, dummySkuDetails.description); expect(response.productDetails.first.price, dummySkuDetails.price); + expect(response.productDetails.first.currencySymbol, r'$'); }); test('should get the correct notFoundIDs', () async { From 45e8d94231560fd0ff0b5865d089418785f0828e Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 8 Jul 2021 16:58:00 +0200 Subject: [PATCH 4/4] fix test --- .../test/billing_client_wrappers/sku_details_wrapper_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart index 7aece605db33..b8ba9d5cc854 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/sku_details_wrapper_test.dart @@ -140,6 +140,7 @@ Map buildSkuMap(SkuDetailsWrapper original) { 'price': original.price, 'priceAmountMicros': original.priceAmountMicros, 'priceCurrencyCode': original.priceCurrencyCode, + 'priceCurrencySymbol': original.priceCurrencySymbol, 'sku': original.sku, 'subscriptionPeriod': original.subscriptionPeriod, 'title': original.title,