@Override
  protected BasicPaymentItems doInBackground(String... params) {

    // Check whether the paymentProducts will be shown in groups
    if (groupPaymentItems) {

      // Create a threadpool that will execute the tasks of getting the paymentproducts and the
      // paymentproductgroups
      ExecutorService executorService = Executors.newFixedThreadPool(2);

      // Create the callables that will be executed
      Callable<BasicPaymentProducts> paymentProductsCallable =
          new BasicPaymentProductsAsyncTask(
              context,
              paymentContext,
              communicator,
              new LinkedList<OnBasicPaymentProductsCallCompleteListener>());
      Callable<BasicPaymentProductGroups> paymentProductGroupsCallable =
          new BasicPaymentProductGroupsAsyncTask(
              context,
              paymentContext,
              communicator,
              new LinkedList<OnBasicPaymentProductGroupsCallCompleteListener>());

      // Retrieve the futures from the callable tasks
      Future<BasicPaymentProducts> paymentProductsFuture =
          executorService.submit(paymentProductsCallable);
      Future<BasicPaymentProductGroups> paymentProductGroupsFuture =
          executorService.submit(paymentProductGroupsCallable);

      try {
        // Retrieve the basicPaymentProducts and basicPaymentProductGroups from the futures
        BasicPaymentProducts basicPaymentProducts = paymentProductsFuture.get();
        BasicPaymentProductGroups basicPaymentProductGroups = paymentProductGroupsFuture.get();

        // Return a list of the basicPaymentProducts and basicPaymentProductGroups combined
        return createBasicPaymentItems(basicPaymentProducts, basicPaymentProductGroups);

      } catch (InterruptedException e) {
        Log.i(TAG, "Error while getting paymentItems: " + e.getMessage());
        e.printStackTrace();
      } catch (ExecutionException e) {
        Log.i(TAG, "Error while getting paymentItems: " + e.getMessage());
        e.printStackTrace();
      }
    } else {

      // Create the paymentProductsCallable
      Callable<BasicPaymentProducts> paymentProductsCallable =
          new BasicPaymentProductsAsyncTask(
              context,
              paymentContext,
              communicator,
              new LinkedList<OnBasicPaymentProductsCallCompleteListener>());
      try {

        // Retrieve the basicPaymentProducts
        BasicPaymentProducts basicPaymentProducts = paymentProductsCallable.call();

        return new BasicPaymentItems(
            basicPaymentProducts.getPaymentProductsAsItems(),
            basicPaymentProducts.getAccountsOnFile());
      } catch (Exception e) {
        Log.i(TAG, "Error while getting paymentItems: " + e.getMessage());
        e.printStackTrace();
      }
    }

    // If an error occurred no valid paymentItems can be returned
    return null;
  }
  private BasicPaymentItems createBasicPaymentItems(
      BasicPaymentProducts basicPaymentProducts,
      BasicPaymentProductGroups basicPaymentProductGroups) {

    // Validate the results of the calls
    if (basicPaymentProducts == null && basicPaymentProductGroups == null) {

      // If both basicPaymentProducts and basicPaymentProductGroups are null, return nul
      return null;

    } else if (basicPaymentProductGroups == null) {

      // If basicPaymentProductGroups == null, return just the basicPaymentProducts
      return new BasicPaymentItems(
          basicPaymentProducts.getPaymentProductsAsItems(),
          basicPaymentProducts.getAccountsOnFile());

    } else if (basicPaymentProducts == null) {

      // If basicPaymentProducts == null, return just the basicPaymentProductGroups
      return new BasicPaymentItems(
          basicPaymentProductGroups.getPaymentProductGroupsAsItems(),
          basicPaymentProductGroups.getAccountsOnFile());
    }

    // Else: Merge the paymentItems together.

    // Create a list of PaymentProductSelectables that will be filled and stored in the
    // basicPaymentItems object that is returned
    List<BasicPaymentItem> basicPaymentItems = new ArrayList<>();

    // Create a list of AccountOnFiles that will be filled and stored in the basicPaymentItems
    // object that is returned
    List<AccountOnFile> accountsOnFile = new LinkedList<>();

    // Filter out all basicPaymentProducts that also have a corresponding paymentProductGroup.
    // Instead add the group to the
    // list of basicPaymentItems that will be returned.
    for (BasicPaymentProduct paymentProduct : basicPaymentProducts.getBasicPaymentProducts()) {

      // Add the accountsOnFile of the current paymentProduct to the collection of accountOnFiles.
      accountsOnFile.addAll(paymentProduct.getAccountsOnFile());

      // becomes true if the paymentProduct has been matched with a group.
      boolean groupMatch = false;

      for (BasicPaymentProductGroup paymentProductGroup :
          basicPaymentProductGroups.getBasicPaymentProductGroups()) {

        // Does the current paymentProduct belong to the current paymentProductGroup
        if (paymentProduct.getPaymentProductGroup() != null
            && paymentProduct.getPaymentProductGroup().equals(paymentProductGroup.getId())) {

          // Add the paymentProductGroup to the basicPaymentItems that will be returned if it is not
          // already in the list
          if (!basicPaymentItems.contains(paymentProductGroup)) {

            // Set the displayOrder of the group to the displayOrder of the first paymentProduct
            // match
            paymentProductGroup
                .getDisplayHints()
                .setDisplayOrder(paymentProduct.getDisplayHints().getDisplayOrder());
            basicPaymentItems.add(paymentProductGroup);
          }

          // Product has been matched to a group
          groupMatch = true;

          // Products can not match with more then one group
          break;
        }
      }
      if (!groupMatch) {

        // If the paymentProduct does not belong to a paymentProductGroup, add the paymentProduct to
        // the
        // basicPaymentItems that will be returned
        basicPaymentItems.add(paymentProduct);
      }
    }

    // Return a new BasicPaymentItems object that contains the paymentItems and the accountsOnFile
    return new BasicPaymentItems(basicPaymentItems, accountsOnFile);
  }