aws-amplify / aws-sdk-android

AWS SDK for Android. For more information, see our web site:
https://docs.amplify.aws
Other
1.03k stars 548 forks source link

[Pinpoint] updateEndpointProfile() throws BadRequestException for the locale information sent by the SDK #589

Closed baole closed 5 years ago

baole commented 5 years ago

Describe the bug pinpointManager?.targetingClient?.updateEndpointProfile() crashes

To Reproduce After creating a Pinpoint manager, I try to update targetingClient and saw a crash log in Android Studio log console

Which AWS service(s) are affected?

Pinpoint

Expected behavior No error log

Environment(please complete the following information):

Device Information (please complete the following information):

I didn't test on other devices yet

Additional context Here is the logs:

2018-11-22 11:52:31.214 8829-10584/net.tandem E/TargetingClient: AmazonServiceException occurred during endpoint update: com.amazonaws.services.pinpoint.model.BadRequestException: Country should be 2 character ISO 3166-1 Alpha-2 or Alpha-3 codes or UN M.49 numeric-3 area code (Service: AmazonPinpoint; Status Code: 400; Error Code: BadRequestException; Request ID: 39a7b932-ee44-11e8-9b8d-6552bb36863b) at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730) at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405) at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212) at com.amazonaws.services.pinpoint.AmazonPinpointClient.invoke(AmazonPinpointClient.java:3885) at com.amazonaws.services.pinpoint.AmazonPinpointClient.updateEndpoint(AmazonPinpointClient.java:3630) at com.amazonaws.mobileconnectors.pinpoint.targeting.TargetingClient$1.run(TargetingClient.java:198) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:762)

baole commented 5 years ago

It looks like the issue was marked as fix #354, but still happening.

mutablealligator commented 5 years ago

@baole Sorry for the inconvenience caused. Can you give a code snippet that reproduces the issue?

baole commented 5 years ago

I just figure out that creating PinpointManager with different context behave differently

This is my test function:

    fun test(context: Context) {
        val callback = object : Callback<UserStateDetails> {
            override fun onError(e: Exception?) {
                e?.printStackTrace()
            }

            override fun onResult(result: UserStateDetails?) {
                val config = PinpointConfiguration(
                        context,
                        AWSMobileClient.getInstance(),
                        AWSMobileClient.getInstance().getConfiguration()
                )

                config.withPostNotificationsInForeground(true)
                        .withAllowsEventCollection(true)
                        .withEnablePinpoint(true)
                val pinpointManager = PinpointManager(config)
                pinpointManager.run {
                    targetingClient?.run {
                        addAttribute("gender", listOf("f"))
                        addAttribute("age", listOf("30"))
                        updateEndpointProfile()
                    }
                    sessionClient.startSession()
                    analyticsClient.submitEvents()
                }
            }
        }
        AWSMobileClient.getInstance().initialize(context, callback)
    }

If I passed Activity or baseContext (from activity.getBaseContext()) as context parameters, it works perfectly. However, the above issue throws when I passed applicationContext (from activity.getApplicationContext()).

@kvasukib Is that an expected behaviour? Or I missed something?

mutablealligator commented 5 years ago

@baole Are you getting the BadRequestException when you pass in application context however you don't get it when you pass the activity context?

I tried passing in the application context and I did not get any exception.

package com.amazonaws.pinpointinstrumentationtester;

import android.app.Application;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobile.config.AWSConfiguration;
import com.amazonaws.mobileconnectors.pinpoint.PinpointConfiguration;
import com.amazonaws.mobileconnectors.pinpoint.PinpointManager;

import java.util.Arrays;

public class MyApplication extends Application {
    private static final String LOG_TAG = MyApplication.class.getSimpleName();
    public static PinpointManager pinpointManager;
    private AbstractApplicationLifeCycleHelper applicationLifeCycleHelper;

    @Override
    public void onCreate() {
        super.onCreate();

        AWSConfiguration awsConfiguration = new AWSConfiguration(this);
        PinpointConfiguration pinpointConfiguration = new PinpointConfiguration(getApplicationContext(),
                new CognitoCachingCredentialsProvider(getApplicationContext(), awsConfiguration),
                awsConfiguration);
        pinpointManager = new PinpointManager(pinpointConfiguration);

        pinpointManager.getTargetingClient().addAttribute("gender", Arrays.asList("male"));
        pinpointManager.getTargetingClient().addAttribute("age", Arrays.asList("27"));
        pinpointManager.getTargetingClient().updateEndpointProfile();
    }
}

Can I know from what locale are you trying to send this endpoint update? You can get this from the following log statements.

Log.d(TAG, "ISO3 Country: " + context.getApplicationContext().getResources().getConfiguration().locale.getISO3Country());

Log.d(TAG, "Country: " + context.getApplicationContext().getResources().getConfiguration().locale.getCountry());

Can you get the values of these two log statements by putting them into your app?

baole commented 5 years ago

Hi @kvasukib

It's not clear where the "context" that uses to get locale come from in your sample code. I tried the code in the "MyApplication" class and in an activity class

In MyApplication class, it shows

D/Pinpoint: ISO3 Country: 
D/Pinpoint: Country: 

In an activity class, it shows

D/Pinpoint: ISO3 Country: USA
D/Pinpoint: Country: US

Here is the code I used for both cases:

        AWSConfiguration awsConfiguration = new AWSConfiguration(this);
        PinpointConfiguration pinpointConfiguration = new PinpointConfiguration(getApplicationContext(),
                new CognitoCachingCredentialsProvider(getApplicationContext(), awsConfiguration),
                awsConfiguration);
        PinpointManager pinpointManager = new PinpointManager(pinpointConfiguration);

        pinpointManager.getTargetingClient().addAttribute("Gender", Arrays.asList("male"));
        pinpointManager.getTargetingClient().addAttribute("Engaged", Arrays.asList("27"));
        pinpointManager.getTargetingClient().updateEndpointProfile();
        Log.d("Pinpoint", "ISO3 Country: " + getResources().getConfiguration().locale.getISO3Country());
        Log.d("Pinpoint", "Country: " + getResources().getConfiguration().locale.getCountry());
mutablealligator commented 5 years ago

@baole The context that is passed through the PinpointConfiguration is stored in PinpointContext object. When trying to get the locale/country information, the SDK does the following:

// Here context refers to the context object that is passed through the `PinpointConfiguration` object.
context.getApplicationContext().getResources().getConfiguration().locale.getISO3Country();
frankmuellr commented 5 years ago

Hello @baole, did @kvasukib's last comment resolve the issue for you?

baole commented 5 years ago

No, it doesn't. I need to pass non-application context instead.

mutablealligator commented 5 years ago

@baole Are you still facing the issue?

baole commented 5 years ago

Yes, it was resolved