Search code examples
androidcredit-cardbraintreebraintree-data

BraintreeHttpClient.setBaseUrl(java.lang.String) on a null object reference


I am using braintree api to get add card in app for payments. It works fines and sometimes crashes randomly,

This is my stacktrace,

E/AndroidRuntime: FATAL EXCEPTION: Thread-833
                                                          Process: cl.tempclick, PID: 29509
                                                          java.lang.NullPointerException: Attempt to invoke virtual method 'com.braintreepayments.api.internal.HttpClient com.braintreepayments.api.internal.BraintreeHttpClient.setBaseUrl(java.lang.String)' on a null object reference
                                                              at com.braintreepayments.api.BraintreeFragment.setConfiguration(BraintreeFragment.java:488)
                                                              at com.braintreepayments.api.BraintreeFragment$5.onConfigurationFetched(BraintreeFragment.java:415)
                                                              at com.braintreepayments.api.ConfigurationManager.getConfiguration(ConfigurationManager.java:46)
                                                              at com.braintreepayments.api.BraintreeFragment.fetchConfiguration(BraintreeFragment.java:412)
                                                              at com.braintreepayments.api.BraintreeFragment.waitForConfiguration(BraintreeFragment.java:458)
                                                              at com.braintreepayments.api.TokenizationClient.tokenize(TokenizationClient.java:72)
                                                              at com.braintreepayments.api.Card.tokenize(Card.java:29)
                                                              at cl.tk.ui.activities.sub_activity.AddPayment$UIThreadHandler$1.run(AddPayment.java:364)
                                                              at java.lang.Thread.run(Thread.java:818)

This is my Code for the activity,

package cl.tk.ui.activities.sub_activity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.braintreepayments.api.BraintreeFragment;
import com.braintreepayments.api.exceptions.InvalidArgumentException;
import    com.braintreepayments.api.interfaces.PaymentMethodNonceCreatedListener;
import com.braintreepayments.api.models.CardBuilder;
import com.braintreepayments.api.models.PaymentMethodNonce;

import cl.tk.R;
import cl.tk.controllers.constants.Constants;
import cl.tk.controllers.constants.Enums_String;
import cl.tk.controllers.listeners.ProcessedResult;
import cl.tk.controllers.rest_api.RetrofitAdapters;
import cl.tk.ui.activities.Register;
import cl.tk.ui.fragments.dialog.DTDialog;
import cl.tk.ui.iBAPViews.editext.pattern.PatternedEditText;
import cl.tk.utility.CreditCard;
import cl.tk.utility.CustomException;
import cl.tek.utility.GeneralFunctions;
import cl.tk.utility.MonthYearPicker;
import cl.tk.utility.Validation;
import cl.tk.utility.fonts.FontsManager;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;


public class AddPayment extends AppCompatActivity implements        View.OnClickListener,View.OnTouchListener, ProcessedResult,PaymentMethodNonceCreatedListener
{
private Handler uiThreadHandler;
private TextView tvExpiryDate;
//private EditText edCvv,ed_cardHOlderName,edZip;
private PatternedEditText edCardNumber;
private MonthYearPicker myp;
private String mClientToken=null;
private CreditCard creditCard =null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_payment);

    uiThreadHandler = new UIThreadHandler();
    initialze();

    downloadBraintreeTOken();
}

private void downloadBraintreeTOken()
{
    RetrofitAdapters.get().getBraintreeToken(new Callback<Response>() {
        @Override
        public void success(Response response, Response response2) {
            parseResult(response);
        }

        @Override
        public void failure(RetrofitError error) {
            uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.HIDEDIALOG);
            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
            message.obj = error.getLocalizedMessage();
            uiThreadHandler.sendMessage(message);
        }
    });
}

private void initialze()
{
    GeneralFunctions.setToolbarMsgIconHide(this, Constants.ToolbarConstants.PAYMENTS, true);

    Button buttonAdd=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_bt_addCard);
    buttonAdd.setOnClickListener(this);
    GeneralFunctions.setColorSelector(ContextCompat.getColor(this, R.color.color175), ContextCompat.getColor(this, R.color.color1A9), buttonAdd);

    TextView tv_defult=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_ct_default);
    tv_defult.setOnClickListener(this);

    FontsManager.initFormAssets(this, Enums_String.FontsNameLato.SEMIBOLD.toString());
    FontsManager.changeFonts(tv_defult);

    edCardNumber=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_ed_cardNumber);
    tvExpiryDate=GeneralFunctions.findViewByIdAndCast(this,R.id.payment_tv_expiryDate);
    tvExpiryDate.setOnTouchListener(this);

    myp = new MonthYearPicker(this);
    myp.build(new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            tvExpiryDate.setText(myp.getSelectedMonth() + 1 + "/" + myp.getSelectedYear());
        }
    }, null);
}

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter(Enums_String.LocalReceiver.INTERENT.toString());
    LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter);
}

@Override
protected void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}

@Override
public void onClick(View v) {
    switch (v.getId())
    {
        case R.id.payment_bt_addCard:
            uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.VALIDATION);
            break;
    }
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_UP)
    {
        if(v.getId()==R.id.payment_tv_expiryDate)
        {
            if(myp.pickerDialog != null && !myp.pickerDialog.isShowing())
                myp.pickerDialog.dismiss();
            myp.show();
        }
        return true;
    }
    return false;
}

@Override
public <IResponse, IMethod, IExtra> void processedResult(IResponse iResponse, IMethod iMethod, IExtra iExtra) {

}


@Override
public <IResponse, IMethod> void processedResult(IResponse iResponse, IMethod iMethod) {
    switch (iMethod.toString())
    {
        case Constants.CallbackConstants.VIEW_ERROR: {
            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SETERROR);
            message.obj=iResponse;
            uiThreadHandler.sendMessage(message);
        }
        break;
        case Constants.CallbackConstants.BACK:
            finish();
            break;
    }
}

@Override
public void onPaymentMethodNonceCreated(final PaymentMethodNonce paymentMethodNonce) {

}


private void setError(String errorMsg) {
    if (errorMsg.equalsIgnoreCase("cardNumber"))
        GeneralFunctions.setError(null,String.format(getString(R.string.ed_error_invalid),edCardNumber.getTag().toString()),edCardNumber);
    else if (errorMsg.equalsIgnoreCase("cardDate"))
        GeneralFunctions.setError(null,String.format(getString(R.string.ed_error_invalid),tvExpiryDate.getTag().toString()),tvExpiryDate);
}



private class UIThreadHandler extends Handler {
    @Override
    public void handleMessage(Message msg)
    {
        switch (msg.what) {
            case Constants.ActivityBasicsCode.CARDERROR:
                GeneralFunctions.setError((CustomException)msg.obj,null,null);
                break;
            case Constants.ActivityBasicsCode.SETERROR:
                setError(msg.obj.toString());
                break;
            case Constants.ActivityBasicsCode.SHOWTOAST:
            {
                String text=(String)msg.obj;
                GeneralFunctions.showToast(text,AddPayment.this);
            }
            break;
            case Constants.ActivityBasicsCode.HIDEDIALOG:
                GeneralFunctions.hideProgressDialog(Constants.DialogConstants.Transparent, AddPayment.this);
                break;
            case Constants.ActivityBasicsCode.SHOWDIALOG:
            {
                DTDialog dtDialog=DTDialog.newInstance();
                GeneralFunctions.showProgressDialog(dtDialog, Constants.DialogConstants.Transparent, AddPayment.this);
            }break;
            case Constants.ActivityBasicsCode.VALIDATION: {
                new Thread(new Runnable() {
                    @Override
                    public void run()
                    {
                        try {
                            if(Validation.validate(AddPayment.this)) {
                                creditCard = new CreditCard(GeneralFunctions.getText(edCardNumber),GeneralFunctions.getText(tvExpiryDate),AddPayment.this);

                                boolean validation = creditCard.validateCard();
                                if (validation) {
                                    if(mClientToken==null) {
                                        downloadBraintreeTOken();
                                        Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
                                        message.obj = getString(R.string.toast_payment_token);
                                        uiThreadHandler.sendMessage(message);
                                        return;
                                    }
                                    BraintreeFragment braintreeFragment= BraintreeFragment.newInstance(AddPayment.this, mClientToken);

                                    if(null==braintreeFragment)
                                    {
                                        Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.SHOWTOAST);
                                        message.obj = getString(R.string.toast_payment_fragment);
                                        uiThreadHandler.sendMessage(message);
                                        uiThreadHandler.sendEmptyMessage(Constants.ActivityBasicsCode.SHOWDIALOG);
                                    }
                                    else {
                                        CardBuilder cardBuilder = new CardBuilder()
                                                .cardNumber(creditCard.getNumber().replaceAll("-", "").trim())
                                                .expirationDate(creditCard.getExpriyDate());
                                        com.braintreepayments.api.Card.tokenize(braintreeFragment, cardBuilder);   //On this line my app crashes randomly
                                    }
                                }
                            }
                        }catch (CustomException e)
                        {
                            Message message = uiThreadHandler.obtainMessage(Constants.ActivityBasicsCode.CARDERROR);
                            message.obj=e;
                            uiThreadHandler.sendMessage(message);
                        } catch (InvalidArgumentException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
                break;
            }
        }
        super.handleMessage(msg);
    }
}

}

This is my gradle version, compile 'com.braintreepayments.api:braintree:2.+'


Solution

  • Full disclosure: I work for Braintree.

    Are you refreshing the client token every time you go through the checkout process as required? I see that you are only downloading the Braintree token from the server if it is null.

    Without having any insight into your CreditCard class or its validateCard method, another possibility may be that the CardBuilder object you are passing into Card.tokenize may not be well-formed. ​

    If you are still having trouble, please reach out to Braintree support for help debugging your integration.