Gensoukyou1337
Gensoukyou1337

Reputation: 1527

Facebook account kit Activity crashes when I apply a custom UI manager

Right now I have to convert the whole codebase of my project to Kotlin, and one of the parts in this involves the Facebook Account Kit, where I have to use my mobile phone number to login to the app, as follows:

val intent = Intent(activity, AccountKitActivity::class.java)
val uiManager = CustomUIManager(ButtonType.CONTINUE, ButtonType.NEXT, TextPosition.ABOVE_BODY, R.style.AccountKitTheme)
val configurationBuilder = AccountKitConfiguration.AccountKitConfigurationBuilder(LoginType.PHONE,
        AccountKitActivity.ResponseType.CODE)
//TODO: disable until I figure out what's going on
//configurationBuilder.setUIManager(uiManager)
configurationBuilder.setReadPhoneStateEnabled(true)
configurationBuilder.setReceiveSMS(true)
val config = configurationBuilder.build();
intent.putExtra(AccountKitActivity.ACCOUNT_KIT_ACTIVITY_CONFIGURATION, config)
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
activity.overridePendingTransition(0, 0)
Log.i("account_kit_login", "start "+config.notificationChannels)
activity.startActivityForResult(intent, ACCOUNT.FACEBOOK.code)

This uiManager's class looks like this:

class CustomUIManager : BaseUIManager {
    private var confirmButton: ButtonType? = null
    private var entryButton: ButtonType? = null
    private var textPosition: TextPosition? = null

    constructor(
            confirmButton: ButtonType,
            entryButton: ButtonType,
            textPosition: TextPosition,
            themeResourceId: Int) : super(themeResourceId) {
        this.confirmButton = confirmButton
        this.entryButton = entryButton
        this.textPosition = textPosition
    }

    private constructor(source: Parcel) : super(source) {
        var s: String? = source.readString()
        val confirmButton = if (s == null) null else ButtonType.valueOf(s)
        s = source.readString()
        val entryButton = if (s == null) null else ButtonType.valueOf(s)
        s = source.readString()
        val textPosition = if (s == null) null else TextPosition.valueOf(s)
        this.confirmButton = confirmButton
        this.entryButton = entryButton
        this.textPosition = textPosition
    }

    override fun getHeaderFragment(state: LoginFlowState): Fragment? {
        val prefix: Int
        val type = 0
        when (state) {
            LoginFlowState.PHONE_NUMBER_INPUT -> prefix = R.string.header_phone_number_input
            LoginFlowState.SENDING_CODE -> {
                prefix = R.string.header_sending_code
                return PlaceholderFragment.newInstance(prefix, type, R.dimen.loading_placeholder_height)
            }
            LoginFlowState.SENT_CODE -> {
                prefix = R.string.header_sent_code
                return PlaceholderFragment.newInstance(prefix, type, R.dimen.loading_placeholder_height)
            }
            LoginFlowState.CODE_INPUT -> prefix = R.string.header_code_input
            LoginFlowState.VERIFYING_CODE -> prefix = R.string.header_verifying_code
            LoginFlowState.VERIFIED, LoginFlowState.ACCOUNT_VERIFIED, LoginFlowState.CONFIRM_ACCOUNT_VERIFIED, LoginFlowState.CONFIRM_INSTANT_VERIFICATION_LOGIN -> prefix = R.string.header_account_verified
            LoginFlowState.ERROR -> prefix = R.string.header_error
            else -> return super.getHeaderFragment(state)
        }
        return PlaceholderFragment.newInstance(prefix, type)
    }

    override fun getBodyFragment(state: LoginFlowState): Fragment? {
        val prefix: Int
        val type = 0
        when (state) {
            LoginFlowState.VERIFIED -> {
                prefix = R.string.body_verified
                return PlaceholderFragment.newInstance(prefix, type, R.dimen.loading_placeholder_height)
            }
            LoginFlowState.ERROR -> {
                prefix = R.string.body_error
                return PlaceholderFragment.newInstance(prefix, type, R.dimen.loading_placeholder_height)
            }
            LoginFlowState.CONFIRM_ACCOUNT_VERIFIED -> {
                prefix = R.string.body_confirm_account_verified
                return PlaceholderFragment.newInstance(prefix, type, R.dimen.loading_placeholder_height)
            }
            else -> return super.getBodyFragment(state)
        }
    }
    //
    //    @Nullable
    //    @Override
    //    public Fragment getFooterFragment(LoginFlowState state) {
    //        String prefix = "";
    //        switch (state) {
    //            case PHONE_NUMBER_INPUT:
    //                prefix = "custom footer phone input";
    //                break;
    //            case EMAIL_INPUT:
    //                prefix = "custom footer email input";
    //                break;
    //            case SENDING_CODE:
    //                prefix = "custom footer sending code";
    //                break;
    //            case SENT_CODE:
    //                prefix = "custom footer sent code";
    //                break;
    //            case CODE_INPUT:
    //                prefix = "custom footer code input";
    //                break;
    //            case EMAIL_VERIFY:
    //                prefix = "custom footer email verify";
    //                break;
    //            case CONFIRM_ACCOUNT_VERIFIED:
    //                prefix = "custom footer confirm account";
    //                break;
    //            case VERIFYING_CODE:
    //                prefix = "custom footer verified code";
    //                break;
    //            case CONFIRM_INSTANT_VERIFICATION_LOGIN:
    //                prefix = "custom footer confirm instant verification login";
    //                break;
    //            case VERIFIED:
    //                prefix = "custom footer verified";
    //                break;
    //            case RESEND:
    //                prefix = "custom footer resend";
    //                break;
    //            case ERROR:
    //                prefix = "custom footer error";
    //                break;
    //            case NONE:
    //                break;
    //        }
    //        return PlaceholderFragment.newInstance(prefix);
    //    }

    override fun getButtonType(state: LoginFlowState): ButtonType? {
        when (state) {
            LoginFlowState.PHONE_NUMBER_INPUT -> return entryButton
            LoginFlowState.EMAIL_INPUT -> return entryButton
            LoginFlowState.CODE_INPUT -> return confirmButton
            else -> return null
        }
    }

    override fun onError(error: AccountKitError?) {
        // handle error
        Trace.d("onError Custom AK: " + error!!.userFacingMessage)
    }

    override fun writeToParcel(dest: Parcel, flags: Int) {
        super.writeToParcel(dest, flags)
        dest.writeString(if (confirmButton != null) confirmButton!!.name else null)
        dest.writeString(if (entryButton != null) entryButton!!.name else null)
        dest.writeString(if (textPosition != null) textPosition!!.name else null)
    }

    companion object {

        val CREATOR: Parcelable.Creator<CustomUIManager> = object : Parcelable.Creator<CustomUIManager> {
            override fun createFromParcel(source: Parcel): CustomUIManager {
                return CustomUIManager(source)
            }

            override fun newArray(size: Int): Array<CustomUIManager?> {
                return arrayOfNulls(size)
            }
        }
    }
}

As seen in the invocation code in the first block, I had to disable the custom UI so the app won't crash. The following is the stacktrace of the crash:

onCommon()-- Feedback channel: {category=2, app_is_inner=0, is_root=0, sub_category=0, exp_key=java.lang.RuntimeException: Unable to start activity ComponentInfo{net.inovidea.playday/com.facebook.accountkit.ui.AccountKitActivity}: java.lang.ArrayIndexOutOfBoundsException: length=3; index=4522062
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2505)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2577)
    at android.app.ActivityThread.access$1000(ActivityThread.java:164)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1462)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:160)
    at android.app.ActivityThread.main(ActivityThread.java:5541)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
 *****
 Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; index=4522062
    at com.facebook.accountkit.ui.AccountKitConfiguration.<init>(AccountKitConfiguration.java:167)
    at com.facebook.accountkit.ui.AccountKitConfiguration.<init>(AccountKitConfiguration.java:38)
    at com.facebook.accountkit.ui.AccountKitConfiguration$1.createFromParcel(AccountKitConfiguration.java:209)
    at com.facebook.accountkit.ui.AccountKitConfiguration$1.createFromParcel(AccountKitConfiguration.java:207)
    at android.os.Parcel.readParcelable(Parcel.java:2265)
    at android.os.Parcel.readValue(Parcel.java:2165)
    at android.os.Parcel.readArrayMapInternal(Parcel.java:2527)
    at android.os.BaseBundle.unparcel(BaseBundle.java:221)
    at android.os.Bundle.getParcelable(Bundle.java:755)
    at android.content.Intent.getParcelableExtra(Intent.java:5127)
    at com.facebook.accountkit.ui.AccountKitActivityBase.onCreate(AccountKitActivityBase.java:58)
    at com.facebook.accountkit.ui.AccountKitActivity.onCreate(AccountKitActivity.java:246)
    at android.app.Activity.performCreate(Activity.java:6093)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2458)
    ... 10 more, app_pack=net.inovidea.playday, client_time=2018-08-24 16:29:48}

When I tried to look at the problematic line in the stacktrace, inside the AccountKitConfiguration class, it apparently points towards the part where it creates a new Int array and fills it up with the designated NotificationChannels. Then again, the class file was a decompiled file, so I 'm not sure if its pointing there is correct or not.

This error does NOT show when I comment out that UIManager setting, weirdly enough.

Is there something wrong with my CustomUIManager?

Upvotes: 1

Views: 200

Answers (0)

Related Questions