Skip to content

NavigableViewsTrackingDelegate clearing TabLayout's OnTabSelectedListeners #302

@danh32

Description

@danh32

Steps to Reproduce the Problem

  1. build Activity with TabLayout and ViewPager, calling TabLayout.setupWithViewPager() in Activity.onCreate()
  2. background and foreground the activity
  3. notice that clicking on TabLayout's tabs no longer changes the ViewPager's selected page

I spent a couple hours debugging this, and it turns out that NavigableViewsTrackingDelegate is manually calling TabLayout.clearOnTabSelectedListeners() for some reason when the Activity is paused. Here's the stacktrace that I printed from a debug break point:

java.lang.RuntimeException
    at com.google.android.material.tabs.TabLayout.clearOnTabSelectedListeners(TabLayout.java:783)
    at com.instabug.library.tracking.g.a(NavigableViewsTrackingDelegate.java:32)
    at com.instabug.library.tracking.g.a(NavigableViewsTrackingDelegate.java:1)
    at com.instabug.library.tracking.InstabugInternalTrackingDelegate.handleActivityPausedEvent(InstabugInternalTrackingDelegate.java:32)
    at com.instabug.library.tracking.a.onActivityPaused(InstabugActivityLifecycleListener.java:1)
    at android.app.Application.dispatchActivityPaused(Application.java:248)
    at android.app.Activity.onPause(Activity.java:1731)
    at androidx.fragment.app.FragmentActivity.onPause(FragmentActivity.java:417)
    at com.robinhood.android.common.ui.RxActivity.onPause(RxActivity.kt:43)
    at com.robinhood.android.common.ui.BaseActivity.onPause(BaseActivity.kt:311)
    at android.app.Activity.performPause(Activity.java:7329)
    at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1465)
    at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4021)
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3986)
    at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3938)
    at android.app.servertransaction.PauseActivityItem.execute(PauseActivityItem.java:45)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Expected Behavior

I wouldn't expect Instabug's SDK to be manually clearing listeners in my screen's views. The code is obfuscated, so it's a bit difficult to tell exactly what's going on, but it seems like NavigableViewsTrackingDelegate is adding some OnTabSelectedListeners using TabLayout.addOnTabSelectedListener, then instead of removing using TabLayout.removeOnTabSelectedListener, it calls TabLayout.clearOnTabSelectedListeners. This is highly destructive since it also clears any OnTabSelectedListeners that our code has set (or in this case, that the TabLayout itself has set).

Actual Behavior

Instabug is clearing listeners in my screen's views. In this case, it breaks the interaction between TabLayout and ViewPager.

Instabug integration code

        Instabug.Builder(app, "...")
            .setInvocationEvents(InstabugInvocationEvent.SHAKE)
            .build()
        Instabug.setWelcomeMessageState(WelcomeMessage.State.DISABLED)
        Instabug.setSessionProfilerState(Feature.State.ENABLED)
        Instabug.setReproStepsState(State.ENABLED_WITH_NO_SCREENSHOTS)
        Instabug.setUserAttribute(KEY_BACKEND, backendName)
        apolloNamespace?.let { Instabug.setUserAttribute(KEY_APOLLO_NAMESPACE, it) }
        CrashReporting.setState(Feature.State.DISABLED)
        Surveys.setAutoShowingEnabled(false)
        BugReporting.setOptions(Option.EMAIL_FIELD_OPTIONAL)
        BugReporting.setReportTypes(BugReporting.ReportType.BUG, BugReporting.ReportType.FEEDBACK)
        BugReporting.setShakingThreshold(250) // default is 650
        Replies.setState(Feature.State.DISABLED)

SDK Version

all

Android Version

all

Device Model

all

[Optional] Project That Reproduces the Issue

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions