I have added the latest ACRA:
compile 'ch.acra:acra:4.8.5'
Configured my App class according to docs:
#ReportsCrashes(
reportSenderFactoryClasses = {com.github.dht.screenger.crash.ParseSenderfactory.class}
)
...
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// The following line triggers the initialization of ACRA
ACRA.init(this);
}
Defined the Sender factory:
public class ParseSenderfactory implements ReportSenderFactory {
// NB requires a no arg constructor.
public ReportSender create(Context context, ACRAConfiguration config){
return new ParseSender();
}
}
The sender:
public class ParseSender implements ReportSender {
#Override
public void send(Context context, CrashReportData report) throws ReportSenderException {
// Get the ParseObject to be send to Parse
CrashReportParseObject crashReport = getParseObject(report);
// Associate the current logged user with the crash report
ParseUser currentUser = ParseUser.getCurrentUser();
crashReport.setUser(currentUser);
// Send crash report to Parse
crashReport.saveInBackground();
}
/**
* Get a custom ParseObject for data collected by ACRA.
* #param report
* Report data collected by ACRA.
* #return
* A custom ParseObject containing relevant data.
*/
private CrashReportParseObject getParseObject(Map<ReportField, String> report) {
ReportField[] fields = ACRA.getConfig().customReportContent();
if (fields.length == 0) {
fields = ACRAConstants.DEFAULT_REPORT_FIELDS;
}
CrashReportParseObject finalReport = new CrashReportParseObject();
for (ReportField field : fields) {
finalReport.put(field.toString(), report.get(field));
}
return finalReport;
}
}
And the ParseObject:
#ParseClassName("CrashReport")
public class CrashReportParseObject extends ParseObject {
public String getAndroidVersion(){
return this.getString("ANDROID_VERSION");
}
public String getAppVersionName(){
return this.getString("APP_VERSION_NAME");
}
public String getPhoneModel(){
return this.getString("PHONE_MODEL");
}
public String getProduct(){
return this.getString("PRODUCT");
}
public void setUser(ParseUser user){
this.put("user", user);
}
}
And yet ACRA does not catch an exception I send from the activity:
#Override
public void onStart() {
super.onStart();
throw new RuntimeException("This is a crash");
}
Did I forget something?
UPDATE
Made some progress. Saw the CrashReportParseObject was not being created as Parse wanted the syntax to be ParseObject.create("CrashReport");
Changed the ParseSender to :
public class ParseSender implements ReportSender {
#Override
public void send(Context context, CrashReportData report) throws ReportSenderException {
Log.d("ACRA", "Sending log");
// Get the ParseObject to be send to Parse
ParseObject crashReport = getParseObject(report);
// Associate the current logged user with the crash report
ParseUser currentUser = ParseUser.getCurrentUser();
crashReport.put("user", currentUser);
Log.d("ACRA", crashReport.toString());
// Send crash report to Parse
crashReport.saveInBackground();
}
/**
* Get a custom ParseObject for data collected by ACRA.
*
* #param report Report data collected by ACRA.
* #return A custom ParseObject containing relevant data.
*/
private ParseObject getParseObject(Map<ReportField, String> report) {
ReportField[] fields = ACRA.getConfig().customReportContent();
if (fields.length == 0) {
fields = ACRAConstants.DEFAULT_REPORT_FIELDS;
}
ParseObject finalReport = new ParseObject("CrashReport");
for (ReportField field : fields) {
if (field.toString() != null && report.get(field) != null) {
finalReport.put(field.toString(), report.get(field));
}
}
return finalReport;
}
}
and removed CrashReportParseObject all together. Now I am getting "ACRA caught a RuntimeException for com.github.dht.screenger" but still no object is being created on parse.com. Is it a timing thing? does the app crash before it gets the time save the object?
Related
Am trying to implement Braintree Vault PayPal payment, the problem am facing here is getting the paymentMethodNonce my event listener createdListener to capture nonce doesn't get called using vault, but everything works fine using checkout. I can't charge customer without a paymentMethodNonce, please can anyone assist me.
mBraintreeFragment = BraintreeFragment.newInstance(this,"TOKEN_FROM_SERVER");
PayPalRequest request = new PayPalRequest().localeCode("US").billingAgreementDescription("Your agreement description");
PayPal.requestBillingAgreement(mBraintreeFragment, request);
mBraintreeFragment.addListener(createdListener);
mBraintreeFragment.addListener(cancelListener);
mBraintreeFragment.addListener(errorListener);
DataCollector.collectDeviceData(mBraintreeFragment, new BraintreeResponseListener<String>() {
#Override
public void onResponse(String deviceData) {
Log.e("PayPal", deviceData);
try {
JSONObject json = new JSONObject(deviceData);
deviceDataInfo = json.getString("correlation_id");
Log.e("PayPal", deviceDataInfo);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
My Listeners
PaymentMethodNonceCreatedListener createdListener = new PaymentMethodNonceCreatedListener() {
#Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
String nonce = paymentMethodNonce.getNonce();
Log.d("PayPal", "nonce id " + nonce);
}
};
BraintreeCancelListener cancelListener = new BraintreeCancelListener() {
#Override
public void onCancel(int requestCode) {
Log.d("CreditCard", "Braintree Error Code " + requestCode);
}
};
BraintreeErrorListener errorListener = new BraintreeErrorListener() {
#Override
public void onError(Exception error) {
if (error instanceof ErrorWithResponse) {
ErrorWithResponse errorWithResponse = (ErrorWithResponse) error;
BraintreeError cardErrors = errorWithResponse.errorFor("creditCard");
if (cardErrors != null) {
List<BraintreeError> errors = cardErrors.getFieldErrors();
String err = Objects.requireNonNull(errors.get(0).getMessage());
Log.d("CreditCard", errors.toString());
}
}
}
};
Instead of adding manually your listeners to that request, it's better to just implement the interface from braintree.
For example, if you want to use the onPaymentMethodNonceCreated() just add "implements PaymentMethodNonceCreatedListener" after your class name.
public class "YourClass" implements PaymentMethodNonceCreatedListener {
//...
}
And then override the method that now the Android Studio is warning you:
#Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
String nonce = paymentMethodNonce.getNonce();
//...
}
This way you can go for everyone of your listeners! Good luck!
Inside the onConsentFormLoaded method it says for “variable ‘form’ is accessed from within inner class must be declared final” but then when I declare it final it then shows a error “variable ‘form’ might not have been initialized” I tried declaring 'private static ConsentForm form" at the top of my class but then it gives a error saying about placing android context classes inside a static field will result in a memory leak so im not sure where to go from here ?
public static void settings()
{
final AppActivity activity = ((AppActivity) Cocos2dxHelper.getActivity());
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
URL privacyUrl = null;
try {
// TODO: Replace with your app’s privacy policy URL.
privacyUrl = new URL(“https://privacy-policy”);
} catch (MalformedURLException e) {
e.printStackTrace();
}
ConsentForm form = new ConsentForm.Builder(getContext(), privacyUrl).withListener(new ConsentFormListener() {
#Override
public void onConsentFormLoaded() {
// Consent form loaded successfully.
Log.i(“consent”, “consent loaded”);
form.show();
}
#Override
public void onConsentFormOpened() {
// Consent form was displayed.
}
#Override
public void onConsentFormClosed(ConsentStatus consentStatus, Boolean userPrefersAdFree) {
}
#Override
public void onConsentFormError(String errorDescription) {
// Consent form error.
Log.i(“consent”, errorDescription);
}
})
.withPersonalizedAdsOption().withNonPersonalizedAdsOption().build();
form.load();
}
});
}
maybe you know is necesary add this agreement form in android
https://developers.google.com/mobile-ads-sdk/docs/dfp/android/eu-consent
i add this code just above the method onCreate on the main_activity.java
ConsentInformation consentInformation = ConsentInformation.getInstance(this);
String[] publisherIds = {"pub-123"};
ConsentInformation.getInstance(this)
.setConsentStatus(ConsentStatus.PERSONALIZED);
ConsentInformation.getInstance(this).
setDebugGeography(DebugGeography.DEBUG_GEOGRAPHY_EEA);
handler = new Handler();
consentInformation.requestConsentInfoUpdate(publisherIds, new ConsentInfoUpdateListener() {
#Override
public void onConsentInfoUpdated(ConsentStatus consentStatus) {
// User's consent status successfully updated.
}
#Override
public void onFailedToUpdateConsentInfo(String errorDescription) {
// User's consent status failed to update.
}
});
URL privacyUrl = null;
try {
// TODO: Replace with your app's privacy policy URL.
privacyUrl = new URL("https://www.123.com/privacy");
} catch (MalformedURLException e) {
e.printStackTrace();
// Handle error.
}
ConsentForm form = new ConsentForm.Builder(this, privacyUrl)
.withListener(new ConsentFormListener() {
#Override
public void onConsentFormLoaded() {
// Consent form loaded successfully.
}
#Override
public void onConsentFormOpened() {
// Consent form was displayed.
}
#Override
public void onConsentFormClosed(
ConsentStatus consentStatus, Boolean userPrefersAdFree) {
// Consent form was closed.
}
#Override
public void onConsentFormError(String errorDescription) {
// Consent form error.
}
})
.withPersonalizedAdsOption()
.withNonPersonalizedAdsOption()
.withAdFreeOption()
.build();
form.load();
form.show();
but the form dont load when i open the app for testing. Where can be the problem. i assume, the line with: DEBUG_GEOGRAPHY_EEA << define the location of the mobile, but i dont see nothing
thanks for your time !
I already have in my application the integration with "in-app-billing-purchase" however I have several activity where I need to be duplicating all the code.
So I thought about leaving everything focused on a single class, I wastancio the class and I arrive if the item was bought.
Just that I have a big problem the "in-app-billing-purchase" uses Listener OnIabPurchaseFinishedListener and QueryInventoryFinishedListener
How can I leave all this organized in a single class and just check with a simple call in my activity?
Calling code:
Billing bl = new Billing(getActivity().getApplicationContext());
if (bl.Comprado())
Toast.makeText(getActivity(), "Comprado", Toast.LENGTH_SHORT).show();
else
Toast.makeText(getActivity(), "Erro comprado", Toast.LENGTH_SHORT).show();
Class I created to be called multiple times
public class Billing {
// Item name for premium status
private static final String SKU_PREMIUM = "premium";
// private static final String SKU_PREMIUM = "tirarbanner";
// Flag set to true when we have premium status
private static boolean mIsPremium = false;
// In-app Billing helper
private IabHelper mAbHelper;
public Billing(Context context) {
String base64EncodedPublicKey = "xxx";
// Create in-app billing helper
mAbHelper = new IabHelper(context, base64EncodedPublicKey);
// and start setup. If setup is successfull, query inventory we already
// own
mAbHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
return;
}
mAbHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
public static boolean Comprado() {
return mIsPremium;
}
/**
* Listener that is called when we finish purchase flow.
*/
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
if (result.isFailure()) {
return;
}
// Purchase was successfull, set premium flag and update interface
if (purchase.getSku().equals(SKU_PREMIUM)) {
mIsPremium = true;
}
}
};
/**
* Listener that's called when we finish querying the items and
* subscriptions we own
*/
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
// Have we been disposed of in the meantime? If so, quit.
if (mAbHelper == null)
return;
// Is it a failure?
if (result.isFailure()) {
return;
}
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
mIsPremium = premiumPurchase != null;
}
};
}
There's already a library for that.
Check android-inapp-billing-v3.
What can I use instead of addAll() method in my adapter, I'm using realm version 2.0.1 and that method is deprecated, I'm trying to get all the data from the API, save it to my database and pass it to my adapter, I'm using like this:
public void getData(int page) {
if (GlobalModel.existeConexao()) {
Call<PedidosResponse> call = ((NavigationMain) getActivity()).apiService.getPedidos(GlobalModel.getToken(), GlobalModel.geEmpresaId(), page);
call.enqueue(new Callback<PedidosResponse>() {
#Override
public void onResponse(Call<PedidosResponse> call, Response<PedidosResponse> response) {
if (response.isSuccessful()) {
for (int i = 0; i < response.body().getPedidos().size(); i++) {
Pedidos mPedido = response.body().getPedidos().get(i);
int myInt = (mPedido.isProjecao()) ? 1 : 0;
if (!mRepositorio.checkIfExists(mPedido.getId())) {
mRepositorio.addPedido(mPedido.getId(), mPedido.getCliente_id(), mPedido.getData_hora(), mPedido.getData_pedido_cliente(), mPedido.getPrevisao_entrega(), mPedido.getFrete_tipo(), myInt, mPedido.getObservacao(), mPedido.getAliquota_projecao(), mPedido.getStatus(), mPedido.getPedido_cliente());
}
}
arraypedidos = mRepositorio.findAllPedidos();
if (mPedidosAdapter == null) {
mPedidosAdapter = new PedidosAdapter(getActivity(), arraypedidos);
listpedidos.setAdapter(mPedidosAdapter);
} else {
mPedidosAdapter.setData(arraypedidos);
}
}
}
#Override
public void onFailure(Call<PedidosResponse> call, Throwable t) {
if (t.getMessage() != null) {
Log.v("pedidos", t.getMessage());
}
}
});
} else {
Toast.makeText(getActivity(), "Verifique sua conexão", Toast.LENGTH_SHORT).show();
}
}
But when I run the app I get this message:
java.lang.UnsupportedOperationException: This method is not supported by RealmResults.
That's because RealmResults is just a set of pointers that satisfy the condition defined in the query. You can't manipulate it, nor should you if you just intend to show every element in your adapter.
In fact, Realm was explicitly designed to simplify the workflow of "downloading data on a background thread and saving the data in a database", and "showing the data downloaded on a background thread automatically on the UI thread".
This is what RealmChangeListener is for.
Simply put, all of this code is unnecessary:
arraypedidos = mRepositorio.findAllPedidos();
if (mPedidosAdapter == null) {
mPedidosAdapter = new PedidosAdapter(getActivity(), arraypedidos);
listpedidos.setAdapter(mPedidosAdapter);
} else {
mPedidosAdapter.setData(arraypedidos);
}
And could be replaced with this:
public class SomeActivity extends AppCompatActivity {
PedidosAdapter pedidosAdapter;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.some_view);
pedidosAdapter = new PedidosAdapter(context, mRepositorio.findAllPedidos());
// set adapter, ...
}
}
And
public class PedidosAdapter extends RealmRecyclerViewAdapter<Pedidos, PedidosViewHolder> {
public PedidosAdapter(Context context, RealmResults<Pedidos> results) {
super(context, results, true);
}
// onBindViewHolder
// onCreateViewHolder
}
For this, use RealmRecyclerViewAdapter, unless you intend to handle the RealmChangeListener manually.