[In_App_Purchase] Avoids possible NullPointerException with background registrations. (#2014)

This PR delays the get of a reference of a Activity instance and raises an error in case of a invalid access to the method that uses it.
diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md
index e7eb3a4..fbbb870 100644
--- a/packages/in_app_purchase/CHANGELOG.md
+++ b/packages/in_app_purchase/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.1+2
+
+* Android: Require a non-null Activity to use the `launchBillingFlow` method.
+
 ## 0.2.1+1
 
 * Remove skipped driver test.
diff --git a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java
index 16ab591..e914d2a 100644
--- a/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java
+++ b/packages/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java
@@ -37,8 +37,8 @@
 public class InAppPurchasePlugin implements MethodCallHandler {
   private static final String TAG = "InAppPurchasePlugin";
   private @Nullable BillingClient billingClient;
-  private final Activity activity;
-  private final Context context;
+  private final Registrar registrar;
+  private final Context applicationContext;
   private final MethodChannel channel;
 
   @VisibleForTesting
@@ -69,13 +69,12 @@
   public static void registerWith(Registrar registrar) {
     final MethodChannel channel =
         new MethodChannel(registrar.messenger(), "plugins.flutter.io/in_app_purchase");
-    channel.setMethodCallHandler(
-        new InAppPurchasePlugin(registrar.context(), registrar.activity(), channel));
+    channel.setMethodCallHandler(new InAppPurchasePlugin(registrar, channel));
   }
 
-  public InAppPurchasePlugin(Context context, Activity activity, MethodChannel channel) {
-    this.context = context;
-    this.activity = activity;
+  public InAppPurchasePlugin(Registrar registrar, MethodChannel channel) {
+    this.applicationContext = registrar.context();
+    this.registrar = registrar;
     this.channel = channel;
   }
 
@@ -114,16 +113,17 @@
   }
 
   @VisibleForTesting
-  /*package*/ InAppPurchasePlugin(@Nullable BillingClient billingClient, MethodChannel channel) {
+  /*package*/ InAppPurchasePlugin(
+      Registrar registrar, @Nullable BillingClient billingClient, MethodChannel channel) {
     this.billingClient = billingClient;
     this.channel = channel;
-    this.context = null;
-    this.activity = null;
+    this.applicationContext = registrar.context();
+    this.registrar = registrar;
   }
 
   private void startConnection(final int handle, final Result result) {
     if (billingClient == null) {
-      billingClient = buildBillingClient(context, channel);
+      billingClient = buildBillingClient(applicationContext, channel);
     }
 
     billingClient.startConnection(
@@ -201,6 +201,17 @@
           null);
       return;
     }
+    final Activity activity = registrar.activity();
+
+    if (activity == null) {
+      result.error(
+          "ACTIVITY_UNAVAILABLE",
+          "Details for sku "
+              + sku
+              + " are not available. This method must be run with the app in foreground.",
+          null);
+      return;
+    }
 
     BillingFlowParams.Builder paramsBuilder =
         BillingFlowParams.newBuilder().setSkuDetails(skuDetails);
diff --git a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java
index 4792505..41a6078 100644
--- a/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java
+++ b/packages/in_app_purchase/example/android/app/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java
@@ -28,6 +28,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.content.Context;
 import androidx.annotation.Nullable;
 import com.android.billingclient.api.BillingClient;
 import com.android.billingclient.api.BillingClient.BillingResponse;
@@ -41,9 +43,11 @@
 import com.android.billingclient.api.SkuDetails;
 import com.android.billingclient.api.SkuDetailsParams;
 import com.android.billingclient.api.SkuDetailsResponseListener;
+import io.flutter.plugin.common.BinaryMessenger;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 import io.flutter.plugin.common.MethodChannel.Result;
+import io.flutter.plugin.common.PluginRegistry;
 import io.flutter.plugins.inapppurchase.InAppPurchasePlugin.PluginPurchaseListener;
 import java.util.HashMap;
 import java.util.List;
@@ -60,11 +64,16 @@
   @Mock BillingClient mockBillingClient;
   @Mock MethodChannel mockMethodChannel;
   @Spy Result result;
+  @Mock PluginRegistry.Registrar registrar;
+  @Mock Activity activity;
+  @Mock BinaryMessenger messenger;
+  @Mock Context context;
 
   @Before
   public void setUp() {
     MockitoAnnotations.initMocks(this);
-    plugin = new InAppPurchasePlugin(mockBillingClient, mockMethodChannel);
+    when(registrar.context()).thenReturn(context);
+    plugin = new InAppPurchasePlugin(registrar, mockBillingClient, mockMethodChannel);
   }
 
   @Test
@@ -219,6 +228,7 @@
 
   @Test
   public void launchBillingFlow_ok_nullAccountId() {
+    when(registrar.activity()).thenReturn(activity);
     // Fetch the sku details first and then prepare the launch billing flow call
     String skuId = "foo";
     queryForSkus(singletonList(skuId));
@@ -246,7 +256,26 @@
   }
 
   @Test
+  public void launchBillingFlow_ok_null_Activity() {
+    // Fetch the sku details first and then prepare the launch billing flow call
+    String skuId = "foo";
+    String accountId = "account";
+    queryForSkus(singletonList(skuId));
+    HashMap<String, Object> arguments = new HashMap<>();
+    arguments.put("sku", skuId);
+    arguments.put("accountId", accountId);
+    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
+
+    plugin.onMethodCall(launchCall, result);
+
+    // Verify we pass the response code to result
+    verify(result).error(contains("ACTIVITY_UNAVAILABLE"), contains("foreground"), any());
+    verify(result, never()).success(any());
+  }
+
+  @Test
   public void launchBillingFlow_ok_AccountId() {
+    when(registrar.activity()).thenReturn(activity);
     // Fetch the sku details first and query the method call
     String skuId = "foo";
     String accountId = "account";
diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml
index 1bd07cd..d3a8cf0 100644
--- a/packages/in_app_purchase/pubspec.yaml
+++ b/packages/in_app_purchase/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
 author:  Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase
-version: 0.2.1+1
+version: 0.2.1+2
 
 
 dependencies:
@@ -33,4 +33,3 @@
 environment:
   sdk: ">=2.0.0-dev.28.0 <3.0.0"
   flutter: ">=1.5.0 <2.0.0"
-