[in_app_purchase] Added userIds to google play purchase (#4020)

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 949fe90..6175462 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.2
+
+* Added support for the obfuscatedAccountId and obfuscatedProfileId in the PurchaseWrapper.
+
 ## 0.1.1
 
 * Added support to request a list of active subscriptions and non-consumed one-time purchases on Android, through the `InAppPurchaseAndroidPlatformAddition.queryPastPurchases` method.
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 37e30cb..079c18a 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
@@ -5,6 +5,7 @@
 package io.flutter.plugins.inapppurchase;
 
 import androidx.annotation.Nullable;
+import com.android.billingclient.api.AccountIdentifiers;
 import com.android.billingclient.api.BillingResult;
 import com.android.billingclient.api.Purchase;
 import com.android.billingclient.api.Purchase.PurchasesResult;
@@ -63,6 +64,11 @@
     info.put("developerPayload", purchase.getDeveloperPayload());
     info.put("isAcknowledged", purchase.isAcknowledged());
     info.put("purchaseState", purchase.getPurchaseState());
+    AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers();
+    if (accountIdentifiers != null) {
+      info.put("obfuscatedAccountId", accountIdentifiers.getObfuscatedAccountId());
+      info.put("obfuscatedProfileId", accountIdentifiers.getObfuscatedProfileId());
+    }
     return info;
   }
 
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 47147e7..e65afcf 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
@@ -5,9 +5,13 @@
 package io.flutter.plugins.inapppurchase;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import androidx.annotation.NonNull;
+import com.android.billingclient.api.AccountIdentifiers;
 import com.android.billingclient.api.BillingClient;
 import com.android.billingclient.api.BillingResult;
 import com.android.billingclient.api.Purchase;
@@ -26,7 +30,7 @@
   private static final String SKU_DETAIL_EXAMPLE_JSON =
       "{\"productId\":\"example\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"Example title\",\"description\":\"Example description.\",\"original_price\":\"$0.99\",\"original_price_micros\":990000}";
   private static final String PURCHASE_EXAMPLE_JSON =
-      "{\"orderId\":\"foo\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}";
+      "{\"orderId\":\"foo\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\", \"obfuscatedAccountId\":\"Account101\", \"obfuscatedProfileId\": \"Profile105\"}";
 
   @Test
   public void fromSkuDetail() throws JSONException {
@@ -64,6 +68,16 @@
   }
 
   @Test
+  public void fromPurchaseWithoutAccountIds() throws JSONException {
+    final Purchase expected =
+        new PurchaseWithoutAccountIdentifiers(PURCHASE_EXAMPLE_JSON, "signature");
+    Map<String, Object> serialized = Translator.fromPurchase(expected);
+    assertNotNull(serialized.get("orderId"));
+    assertNull(serialized.get("obfuscatedProfileId"));
+    assertNull(serialized.get("obfuscatedAccountId"));
+  }
+
+  @Test
   public void fromPurchaseHistoryRecord() throws JSONException {
     final PurchaseHistoryRecord expected =
         new PurchaseHistoryRecord(PURCHASE_EXAMPLE_JSON, "signature");
@@ -200,6 +214,14 @@
     assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload"));
     assertEquals(expected.isAcknowledged(), serialized.get("isAcknowledged"));
     assertEquals(expected.getPurchaseState(), serialized.get("purchaseState"));
+    assertNotNull(expected.getAccountIdentifiers().getObfuscatedAccountId());
+    assertEquals(
+        expected.getAccountIdentifiers().getObfuscatedAccountId(),
+        serialized.get("obfuscatedAccountId"));
+    assertNotNull(expected.getAccountIdentifiers().getObfuscatedProfileId());
+    assertEquals(
+        expected.getAccountIdentifiers().getObfuscatedProfileId(),
+        serialized.get("obfuscatedProfileId"));
   }
 
   private void assertSerialized(PurchaseHistoryRecord expected, Map<String, Object> serialized) {
@@ -211,3 +233,15 @@
     assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload"));
   }
 }
+
+class PurchaseWithoutAccountIdentifiers extends Purchase {
+  public PurchaseWithoutAccountIdentifiers(@NonNull String s, @NonNull String s1)
+      throws JSONException {
+    super(s, s1);
+  }
+
+  @Override
+  public AccountIdentifiers getAccountIdentifiers() {
+    return null;
+  }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart
index 7ef089f..374c26a 100644
--- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart
+++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart
@@ -4,6 +4,7 @@
 
 import 'dart:ui' show hashValues;
 import 'package:flutter/foundation.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
 import 'package:json_annotation/json_annotation.dart';
 import 'enum_converters.dart';
 import 'billing_client_wrapper.dart';
@@ -26,18 +27,21 @@
 class PurchaseWrapper {
   /// Creates a purchase wrapper with the given purchase details.
   @visibleForTesting
-  PurchaseWrapper(
-      {required this.orderId,
-      required this.packageName,
-      required this.purchaseTime,
-      required this.purchaseToken,
-      required this.signature,
-      required this.sku,
-      required this.isAutoRenewing,
-      required this.originalJson,
-      this.developerPayload,
-      required this.isAcknowledged,
-      required this.purchaseState});
+  PurchaseWrapper({
+    required this.orderId,
+    required this.packageName,
+    required this.purchaseTime,
+    required this.purchaseToken,
+    required this.signature,
+    required this.sku,
+    required this.isAutoRenewing,
+    required this.originalJson,
+    this.developerPayload,
+    required this.isAcknowledged,
+    required this.purchaseState,
+    this.obfuscatedAccountId,
+    this.obfuscatedProfileId,
+  });
 
   /// Factory for creating a [PurchaseWrapper] from a [Map] with the purchase details.
   factory PurchaseWrapper.fromJson(Map<String, dynamic> map) =>
@@ -136,6 +140,20 @@
   /// [BillingClient.acknowledgePurchase] should only be called when the `purchaseState` is [PurchaseStateWrapper.purchased].
   /// * See also [BillingClient.acknowledgePurchase] for more details on acknowledging purchases.
   final PurchaseStateWrapper purchaseState;
+
+  /// The obfuscatedAccountId specified when making a purchase.
+  ///
+  /// The [obfuscatedAccountId] can either be set in
+  /// [PurchaseParam.applicationUserName] when using the [InAppPurchasePlatform]
+  /// or by setting the [accountId] in [BillingClient.launchBillingFlow].
+  final String? obfuscatedAccountId;
+
+  /// The obfuscatedProfileId can be used when there are multiple profiles
+  /// withing one account. The obfuscatedProfileId should be specified when
+  /// making a purchase. This property can only be set on a purchase by
+  /// directly calling [BillingClient.launchBillingFlow] and is not available
+  /// on the generic [InAppPurchasePlatform].
+  final String? obfuscatedProfileId;
 }
 
 /// Data structure representing a purchase history record.
diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart
index 5f0d936..5607dbd 100644
--- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart
+++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart
@@ -20,6 +20,8 @@
     isAcknowledged: json['isAcknowledged'] as bool? ?? false,
     purchaseState:
         const PurchaseStateConverter().fromJson(json['purchaseState'] as int?),
+    obfuscatedAccountId: json['obfuscatedAccountId'] as String?,
+    obfuscatedProfileId: json['obfuscatedProfileId'] as String?,
   );
 }
 
@@ -37,6 +39,8 @@
       'isAcknowledged': instance.isAcknowledged,
       'purchaseState':
           const PurchaseStateConverter().toJson(instance.purchaseState),
+      'obfuscatedAccountId': instance.obfuscatedAccountId,
+      'obfuscatedProfileId': instance.obfuscatedProfileId,
     };
 
 PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) {
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 4e78874..900fa43 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 @@
 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.1
+version: 0.1.2
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart
index a3e80a8..bb7ff85 100644
--- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart
+++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart
@@ -19,6 +19,8 @@
   developerPayload: 'dummy payload',
   isAcknowledged: true,
   purchaseState: PurchaseStateWrapper.purchased,
+  obfuscatedAccountId: 'Account101',
+  obfuscatedProfileId: 'Profile103',
 );
 
 final PurchaseWrapper dummyUnacknowledgedPurchase = PurchaseWrapper(
@@ -191,6 +193,8 @@
     'developerPayload': original.developerPayload,
     'purchaseState': PurchaseStateConverter().toJson(original.purchaseState),
     'isAcknowledged': original.isAcknowledged,
+    'obfuscatedAccountId': original.obfuscatedAccountId,
+    'obfuscatedProfileId': original.obfuscatedProfileId,
   };
 }