nambicompany / expandable-fab

A highly customizable 'speed dial' FloatingActionButton implementation.
https://nambicompany.github.io/expandable-fab/
MIT License
200 stars 21 forks source link

Weird NullpointerException when removing fabOption #38

Closed Pezcraft closed 3 years ago

Pezcraft commented 3 years ago

I am doing this... private void removeFabOption(FabOption fabOption) { expandableFabLayout.getPortraitConfiguration().getFabOptions().remove(fabOption); }

and get this exception... E/AndroidRuntime: FATAL EXCEPTION: main Process: com.pezcraft.myapplication, PID: 30800 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getVisibility()' on a null object reference at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3416) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1944) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1633) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7943) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092) at android.view.Choreographer.doCallbacks(Choreographer.java:893) at android.view.Choreographer.doFrame(Choreographer.java:812) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078) at android.os.Handler.handleCallback(Handler.java:907) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7625) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987) I/Process: Sending signal. PID: 30800 SIG: 9

But what's weird is that it worked at first but when I started it a 2nd, 3rd, ... time, I got this exception.

By the way, I am calling the function inside onBillingSetupFinished Listener. It worked perfectly outside the listener. `

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    expandableFabLayout = findViewById(R.id.expandableFabLayout);

    prefManager = new PrefManager(getApplicationContext());

    checkBox = findViewById(R.id.checkBox);
    linearLayoutHighestHeartrate = findViewById(R.id.linearLayoutHighestHeartrate);
    textViewHighestHeartrate = findViewById(R.id.textViewHighestHeartrate);

    //if it's still the same day, do not reset the highest heartrate of the day
    if(prefManager.getHighestHeartrateDate().equals(DateConverter.toDate(new Date()))) {
        highestHeartrate = prefManager.getHighestHeartrate();
    }
    textViewHighestHeartrate.setText(getString(R.string.textViewHighestHeartrate, highestHeartrate));

    //check subscription status
    billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build();
    billingClient.startConnection(new BillingClientStateListener() {
        @Override
        public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK){
                billingClient.queryPurchasesAsync(SkuType.SUBS, (billingResult1, queryPurchasesSubs) -> {
                    if (queryPurchasesSubs.size() > 0){
                        handlePurchases(queryPurchasesSubs);
                    } else {
                        //if no item in purchase list means no, cancelled, or paused subscription
                        prefManager.setPremium(false);
                        removeFabOption(findViewById(R.id.fabOptionPremium));
                    }

                    //set keeprunning-checkbox
                    if(prefManager.isPremium() && prefManager.getKeepRunning()) {
                        checkBox.setChecked(true);
                    }

                    billingClient.queryPurchasesAsync(SkuType.INAPP, (billingResult2, queryPurchasesOnetime) -> {
                        if (queryPurchasesOnetime.size() > 0){
                            handlePurchases(queryPurchasesOnetime);
                        } else {
                            //if no item in purchase list means no, cancelled, or paused subscription
                            prefManager.setPremium(false);
                            removeFabOption(findViewById(R.id.fabOptionPremium));
                        }

                        //set keeprunning-checkbox
                        if(prefManager.isPremium() && prefManager.getKeepRunning()) {
                            checkBox.setChecked(true);
                        }
                    });
                });

                //query prices for BottomSheetDialog
                getSubPrice();
                getOnetimePrice();
            }
        }

        @Override
        public void onBillingServiceDisconnected() {
            Log.d(DEBUG, "Billing Service disconnected.");
        }
    });`

Any ideas, how I can use it inside the listener?

kabumere commented 3 years ago

Hey @Pezcraft,

  1. Are you sure the exception is stemming from the expandableFabLayout.getPortraitConfiguration().getFabOptions().remove call?
    • EDIT: Can I see the full stack trace?
  2. Can you add some logging and try to reproduce the issue? I'm curious to the value of findViewById(R.id.fabOptionPremium) before you pass it to the removeFabOption function. Is it null already at this point?
  3. How long does it take for the query of purchases callback to be invoked? By the time it is invoked, have you already switched screens/fragments/activities? Is the ExpandableFab no longer being shown?
  4. Can you post your full XML layout file for your Activity?
Pezcraft commented 3 years ago
  1. 100% sure, it happens only when I remove the fabOption inside the purchase callback

    Install successfully finished in 2 s 946 ms.
    $ adb shell am start -n "com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
    Connected to process 13820 on device 'huawei-ane_lx1-9WV7N18928005405'.
    Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
    I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#256
    I/HwApiCacheMangerEx: apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#256
    I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#0
    I/HwApiCacheMangerEx: apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#0
    I/t.myapplicatio: QarthPatchMonintor::Init
    QarthPatchMonintor::StartWatch
    I/t.myapplicatio: QarthPatchMonintor::WatchPackage: /data/hotpatch/fwkhotpatch/
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/com.pezcraft.myapplication
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/all
    QarthPatchMonintor::Run
    I/t.myapplicatio: QarthPatchMonintor::Reading
    QarthPatchMonintor::CheckNotifyEvent
    QarthPatchMonintor::CheckNotifyEvent before read
    I/AwareBitmapCacher: init processName:com.pezcraft.myapplication pid=13820 uid=10285
    D/ZrHung.AppEyeUiProbe: notify runnable to start.
    D/ZrHung.AppEyeUiProbe: Runnable thread started.
    D/IMonitor: Load library imonitor_jni
    E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
    W/ZrHung.AppEyeUiProbe: Failed to get config from zrhung
    V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.9}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.9} for app:com.pezcraft.myapplication
    E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
    E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile@e1ab1de
    V/HwPolicyFactory: : success to get AllImpl object and return....
    V/ActivityThread: callActivityOnCreate
    W/t.myapplicatio: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
    W/t.myapplicatio: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
    I/HwApsImpl: APS: new HwApsImpl created
    V/HwWidgetFactory: : successes to get AllImpl object and return....
    I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
    I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
    E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
    W/t.myapplicatio: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
    W/t.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
    W/t.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
    I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@dc2c6a8,com.pezcraft.heartrateonstream.IntroActivity@e251eb6
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
    I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@8d1a554,com.pezcraft.heartrateonstream.IntroActivity@e251eb6
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
    D/TextView: get Display Panel Type is : 0
    I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@3f29bf9,com.pezcraft.heartrateonstream.IntroActivity@e251eb6
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
    I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
    D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@ab7feb5,com.pezcraft.heartrateonstream.IntroActivity@e251eb6
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
    W/t.myapplicatio: Accessing hidden field Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; (light greylist, reflection)
    D/ActivityThread: add activity client record, r= ActivityRecord{2f64f6d token=android.os.BinderProxy@c595c1d {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@c595c1d
    D/ZrHung.AppEyeUiProbe: notify runnable to start.
    D/ZrHung.AppEyeUiProbe: stop checker.
    W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@a6137a2
    D/ZrHung.AppEyeUiProbe: notify runnable to start.
    V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.9}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.9} for app:com.pezcraft.myapplication
    V/ActivityThread: callActivityOnCreate
    I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
    I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
    W/System.err: Defaulting Uptime to NOIMPL due to (java.lang.UnsupportedOperationException) Implementation not available in this environment
    W/System.err: 2021-10-26 13:35:03.649:INFO::main: Logging initialized @-1ms to org.eclipse.jetty.util.log.StdErrLog
    D/ActivityThread: add activity client record, r= ActivityRecord{5dd8f4e token=android.os.BinderProxy@a6137a2 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.MobileMainActivity}} token= android.os.BinderProxy@a6137a2
    D/ZrHung.AppEyeUiProbe: notify runnable to start.
    D/NetworkSecurityConfig: No Network Security Config specified, using platform default
    D/OpenGLRenderer: Skia GL Pipeline
    I/HwSecImmHelper: mSecurityInputMethodService is null
    D/HwAppInnerBoostImpl: set config for com.pezcraft.myapplication BOOST_FLAG=false REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
    D/OpenGLRenderer:   HWUI Binary is  enabled
    I/System.out: Connecting to: ws://192.168.1.102:4444.
    I/HiTouch_HiTouchSensor: enabledInPad = false,isPcCastMode = false
    D/HiTouch_PressGestureDetector: onAttached, package=com.pezcraft.myapplication, windowType=1, mHiTouchRestricted=false
    D/HeartRateOnStream: Get Premium
    Get Premium
    D/AndroidRuntime: Shutting down VM
    W/t.myapplicatio: Accessing hidden method Lcom/msic/qarth/PatchStore;->createDisableExceptionQarthFile(Ljava/lang/Throwable;)Z (blacklist, JNI)
    E/t.myapplicatio: [qarth_debug:]  get PatchStore::createDisableExceptionQarthFile method fail.
    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.pezcraft.myapplication, PID: 13820
    java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getVisibility()' on a null object reference
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3416)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1944)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1633)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7943)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
        at android.view.Choreographer.doCallbacks(Choreographer.java:893)
        at android.view.Choreographer.doFrame(Choreographer.java:812)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
        at android.os.Handler.handleCallback(Handler.java:907)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:216)
        at android.app.ActivityThread.main(ActivityThread.java:7625)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
    I/Process: Sending signal. PID: 13820 SIG: 9
  2. I did this now...

    billingClient.queryPurchasesAsync(SkuType.SUBS, (billingResult1, queryPurchasesSubs) -> {
    if (queryPurchasesSubs.size() > 0){
        handlePurchases(queryPurchasesSubs);
    } else {
        //if no item in purchase list means no, cancelled, or paused subscription
        prefManager.setPremium(false);
        FabOption fabOption = findViewById(R.id.fabOptionPremium);
        Log.d(DEBUG, fabOption.getLabel().getLabelText().toString());
        removeFabOption(fabOption);
    }
    
    //set keeprunning-checkbox
    if(prefManager.isPremium() && prefManager.getKeepRunning()) {
        checkBox.setChecked(true);
    }
    
    billingClient.queryPurchasesAsync(SkuType.INAPP, (billingResult2, queryPurchasesOnetime) -> {
        if (queryPurchasesOnetime.size() > 0){
            handlePurchases(queryPurchasesOnetime);
        } else {
            //if no item in purchase list means no, cancelled, or paused subscription
            prefManager.setPremium(false);
            removeFabOption(findViewById(R.id.fabOptionPremium));
        }
    
        //set keeprunning-checkbox
        if(prefManager.isPremium() && prefManager.getKeepRunning()) {
            checkBox.setChecked(true);
        }
    });
    });
    private void removeFabOption(FabOption fabOption) {
        Log.d(DEBUG, fabOption.getLabel().getLabelText().toString());
        expandableFabLayout.getPortraitConfiguration().getFabOptions().remove(fabOption);
    }

    As you see from D/HeartRateOnStream: Get Premium (see stacktrace) the fabOption is not null inside and outside removeFabOption.

  3. It's very fast. There is no chance to open any other activity. I am staying inside my MainActivity.

  4. 
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_container"
    android:transitionName="shared_container"
    tools:context=".MobileMainActivity">
    
    <ImageView
        android:id="@+id/imageViewHeartrate"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:contentDescription="@string/imageViewHeartDescription"
        app:layout_anchorGravity="end|bottom"
        app:layout_constraintBottom_toTopOf="@+id/textViewHeartrate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/ic_heart" />
    
    <ImageView
        android:id="@+id/imageViewHeartrateDrop"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:alpha="0.75"
        android:contentDescription="@string/imageViewHeartDescription"
        app:layout_anchorGravity="end|bottom"
        app:layout_constraintBottom_toTopOf="@+id/textViewHeartrate"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/ic_heart" />
    
    <TextView
        android:id="@+id/textViewHeartrate"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/textViewNoHeartRate"
        android:textAlignment="center"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <TextView
        android:id="@+id/textViewInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/textViewNoWatch"
        android:textAlignment="center"
        android:textSize="18sp"
        app:layout_constraintTop_toBottomOf="@id/textViewHeartrate" />
    
    <TextView
        android:id="@+id/textViewInfoOBS"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/textViewInfoOBSNotConnected"
        android:textAlignment="center"
        android:textSize="18sp"
        app:layout_constraintTop_toBottomOf="@+id/textViewInfo" />
    
    <LinearLayout
        android:id="@+id/linearLayoutkeepRunningCheckbox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        android:gravity="center|top"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textViewInfoOBS">
    
        <CheckBox
            android:id="@+id/checkBox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:onClick="onClickCheckBoxOption"
            android:text="@string/checkBoxKeepRunning" />
    </LinearLayout>
    
    <LinearLayout
        android:id="@+id/linearLayoutHighestHeartrate"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:gravity="center"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">
    
        <TextView
            android:id="@+id/textViewHighestHeartrate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18sp" />
    
        <ImageView
            android:id="@+id/imageViewHighestHeartrate"
            android:layout_width="16sp"
            android:layout_height="16sp"
            android:contentDescription="@string/imageViewHeartDescription"
            app:srcCompat="@drawable/ic_hideheartrate" />
    </LinearLayout>
    
    <com.nambimobile.widgets.efab.ExpandableFabLayout
        android:id="@+id/expandableFabLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:transitionName="shared_container">
    
        <com.nambimobile.widgets.efab.Overlay
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:overlay_alpha="0"
            app:overlay_orientation="portrait" />
    
        <com.nambimobile.widgets.efab.ExpandableFab
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_marginEnd="15dp"
            android:layout_marginBottom="15dp"
            android:contentDescription="@string/descriptionFabMenu"
            app:efab_orientation="portrait" />
    
        <com.nambimobile.widgets.efab.FabOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickConnectOption"
            android:contentDescription="@string/descriptionFabMenuConnect"
            app:fab_icon="@drawable/ic_connect"
            app:fab_orientation="portrait"
            app:label_hiddenToVisibleAnimationDurationMs="5"
            app:label_text="Connect"
            app:label_visibleToHiddenAnimationDurationMs="5" />
    
        <com.nambimobile.widgets.efab.FabOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickTutorialOption"
            android:contentDescription="@string/descriptionFabMenuTutorial"
            app:fab_icon="@drawable/ic_tutorial"
            app:fab_orientation="portrait"
            app:label_hiddenToVisibleAnimationDurationMs="5"
            app:label_text="Tutorial"
            app:label_visibleToHiddenAnimationDurationMs="5" />
    
        <com.nambimobile.widgets.efab.FabOption
            android:id="@+id/fabOptionPremium"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickPremiumOption"
            android:contentDescription="@string/descriptionFabMenuPremium"
            app:fab_icon="@drawable/ic_premium"
            app:fab_orientation="portrait"
            app:label_hiddenToVisibleAnimationDurationMs="5"
            app:label_text="Get Premium"
            app:label_visibleToHiddenAnimationDurationMs="5" />
    
        <com.nambimobile.widgets.efab.FabOption
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClickSettingsOption"
            android:contentDescription="@string/descriptionFabMenuSettings"
            app:fab_icon="@drawable/ic_settings"
            app:fab_orientation="portrait"
            app:label_hiddenToVisibleAnimationDurationMs="5"
            app:label_text="Settings"
            app:label_visibleToHiddenAnimationDurationMs="5" />
    
    </com.nambimobile.widgets.efab.ExpandableFabLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

kabumere commented 3 years ago

Hey @Pezcraft,

Without more logging, I can't really see where exactly the issue is occurring. It could be at the first removeFabOption call inside the first callback... or maybe the first one completes successfully and it's actually occurring at the 2nd removeFabOption call in the 2nd callback (where you don't have logging).

In either case, that gives me some ideas:

1) Comment out the FabOption removal in the 2nd queryPurchasesAsync call and see if you can still reproduce the crash. I'm wondering if the callbacks for SkuType.SUBS and SkuType.INAPP are being invoked at the same time and causing some type of internal race condition within the Android SDK (i.e. while we're in the middle of removing a FabOption from the screen, you try to remove the same fab option, and leading to an illegal state somehow). See if only having the first queryPurchasesAsync callback contain the removeFabOption call fixes the issue. 2) If suggestion number 1 above still results in the same crash, try to remove the Premium FabOption by index instead of by object. So in your case, I think that would be removing index 2. 3) If neither suggestion 1 nor 2 works, please add more logging so we can see where it finally breaks. Something before and after each removeFabOption in both callbacks. And please have the logging statements be distinct (and not just the label name each time). Though I would still like to know if the FabOption is null by the time it gets to the 2nd callback.

EDIT: The stacktrace also doesn't show where from your code (or the library) the issue stems... I'm leaning towards something along the lines of number 1 above being the issue.

Pezcraft commented 3 years ago

I am sorry for the bad logging. Now I did this... (by the way, neither 1 nor 2 works)

private void removeFabOption(FabOption fabOption) {
    Log.d(DEBUG, "inside-remove (removing...)" + fabOption.toString());
    expandableFabLayout.getPortraitConfiguration().getFabOptions().remove(fabOption);
    Log.d(DEBUG, "inside-remove (removed)" + fabOption.toString());
}
billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK){
            billingClient.queryPurchasesAsync(SkuType.SUBS, (billingResult1, queryPurchasesSubs) -> {
                if (queryPurchasesSubs.size() > 0){
                    handlePurchases(queryPurchasesSubs);
                } else {
                    //if no item in purchase list means no, cancelled, or paused subscription
                    prefManager.setPremium(false);
                    FabOption fabOption = findViewById(R.id.fabOptionPremium);
                    Log.d(DEBUG, "subs-before-remove-" + fabOption.toString());
                    removeFabOption(fabOption);
                    Log.d(DEBUG, "subs-after-remove-" + fabOption.toString());
                }

                //set keeprunning-checkbox
                if(prefManager.isPremium() && prefManager.getKeepRunning()) {
                    checkBox.setChecked(true);
                }

                billingClient.queryPurchasesAsync(SkuType.INAPP, (billingResult2, queryPurchasesOnetime) -> {
                    if (queryPurchasesOnetime.size() > 0){
                        handlePurchases(queryPurchasesOnetime);
                    } else {
                        //if no item in purchase list means no, cancelled, or paused subscription
                        prefManager.setPremium(false);
                        FabOption fabOption = findViewById(R.id.fabOptionPremium);
                        Log.d(DEBUG, "inapp-before-remove-" + fabOption.toString());
                        removeFabOption(findViewById(R.id.fabOptionPremium));
                        Log.d(DEBUG, "inapp-after-remove-" + fabOption.toString());
                    }

                    //set keeprunning-checkbox
                    if(prefManager.isPremium() && prefManager.getKeepRunning()) {
                        checkBox.setChecked(true);
                    }
                });
            });

            //query prices for BottomSheetDialog
            getSubPrice();
            getOnetimePrice();
        }
    }

    @Override
    public void onBillingServiceDisconnected() {
        Log.d(DEBUG, "Billing Service disconnected.");
    }
});

My first execution (it worked)

10/27 08:50:06: Launching 'mobile' on HUAWEI ANE-LX1.
Install successfully finished in 3 s 33 ms.
$ adb shell am start -n "com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 29454 on device 'huawei-ane_lx1-9WV7N18928005405'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/t.myapplicatio: Late-enabling -Xcheck:jni
I/t.myapplicatio: Reinit property: dalvik.vm.checkjni= false
D/ZrHung.AppEyeUiProbe: AppEyeUIP created.
D/ActivityThread: Attach thread to application
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#256
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#256
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#0
I/HwApiCacheMangerEx: apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#0
I/t.myapplicatio: QarthPatchMonintor::Init
    QarthPatchMonintor::StartWatch
    QarthPatchMonintor::WatchPackage: /data/hotpatch/fwkhotpatch/
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/com.pezcraft.myapplication
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/all
    QarthPatchMonintor::Run
I/t.myapplicatio: QarthPatchMonintor::Reading
I/t.myapplicatio: QarthPatchMonintor::CheckNotifyEvent
    QarthPatchMonintor::CheckNotifyEvent before read
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: Runnable thread started.
D/IMonitor: Load library imonitor_jni
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
W/ZrHung.AppEyeUiProbe: Failed to get config from zrhung
I/AwareBitmapCacher: init processName:com.pezcraft.myapplication pid=29454 uid=10285
E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile@7b0d00c
V/HwPolicyFactory: : success to get AllImpl object and return....
V/ActivityThread: callActivityOnCreate
W/t.myapplicatio: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
W/t.myapplicatio: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
I/HwApsImpl: APS: new HwApsImpl created
V/HwWidgetFactory: : successes to get AllImpl object and return....
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/t.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@23f6ee6,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@2039372,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
D/TextView: get Display Panel Type is : 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@aaec91f,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@a80d83b,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
W/t.myapplicatio: Accessing hidden field Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; (light greylist, reflection)
D/ActivityThread: add activity client record, r= ActivityRecord{40413b3 token=android.os.BinderProxy@44787e3 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@44787e3
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
V/ActivityThread: callActivityOnCreate
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/System.err: Defaulting Uptime to NOIMPL due to (java.lang.UnsupportedOperationException) Implementation not available in this environment
W/System.err: 2021-10-27 08:50:07.516:INFO::main: Logging initialized @-1ms to org.eclipse.jetty.util.log.StdErrLog
D/ActivityThread: add activity client record, r= ActivityRecord{59387ef token=android.os.BinderProxy@32f1d70 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.MobileMainActivity}} token= android.os.BinderProxy@32f1d70
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
D/OpenGLRenderer: Skia GL Pipeline
I/HwSecImmHelper: mSecurityInputMethodService is null
D/HwAppInnerBoostImpl: set config for com.pezcraft.myapplication BOOST_FLAG=false REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
D/OpenGLRenderer:   HWUI Binary is  enabled
I/System.out: Connecting to: ws://192.168.1.102:4444.
I/HiTouch_HiTouchSensor: enabledInPad = false,isPcCastMode = false
D/HiTouch_PressGestureDetector: onAttached, package=com.pezcraft.myapplication, windowType=1, mHiTouchRestricted=false
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=true, mIsFloating=false
D/HeartRateOnStream: subs-before-remove-com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removing...)com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/iGraphics: [0020080c] pn: com.pezcraft.myapplication, p: 29454
    [0030080c] no spt app: com.pezcraft.myapplication
I/OpenGLRenderer: Initialized EGL, version 1.4, mEglDisplay 0x1
D/OpenGLRenderer: Swap behavior 2
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
W/InputMethodManager: startInputReason = 1
W/InputMethodManager: startInputReason = 5
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
D/ActivityThread: Remove activity client record, r= ActivityRecord{40413b3 token=android.os.BinderProxy@44787e3 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@44787e3
D/ZrHung.AppEyeUiProbe: Current Activity:true
D/AwareBitmapCacher: handleInit switch not opened pid=29454
W/Settings: Setting device_provisioned has moved from android.provider.Settings.Secure to android.provider.Settings.Global.
V/HiTouch_HiTouchSensor: User setup is finished.
I/ViewRootImpl: jank_removeInvalidNode jank list is null
V/AudioManager: playSoundEffect   effectType: 0
    querySoundEffectsEnabled...
I/t.myapplicatio: Starting profile saver IsSaveProfileNow end.
V/AudioManager: playSoundEffect   effectType: 0
V/AudioManager: querySoundEffectsEnabled...
W/System.err: 2021-10-27 08:50:22.816:WARN:oejwce.JettyAnnotatedEventDriver:HttpClient@9032ecc-scheduler-1: Unable to report throwable to websocket (no @OnWebSocketError handler declared): net.twasi.obsremotejava.obsremotejava.OBSCommunicator
    java.net.SocketTimeoutException: Connect Timeout
        at org.eclipse.jetty.io.ManagedSelector$Connect.run(ManagedSelector.java:918)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:784)
W/System.err: Failed to setup connection with OBS.
    java.util.concurrent.ExecutionException: java.net.SocketTimeoutException: Connect Timeout
W/System.err:     at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:359)
        at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1921)
        at net.twasi.obsremotejava.obsremotejava.OBSRemoteController.connect(OBSRemoteController.java:69)
        at com.pezcraft.heartrateonstream.MobileMainActivity.lambda$connectToOBS$5$MobileMainActivity(MobileMainActivity.java:398)
        at com.pezcraft.heartrateonstream.-$$Lambda$MobileMainActivity$cxH4bxEAvf7oPiTJ_48syvzscm4.run(Unknown Source:2)
        at java.lang.Thread.run(Thread.java:784)
W/System.err: Caused by: java.net.SocketTimeoutException: Connect Timeout
        at org.eclipse.jetty.io.ManagedSelector$Connect.run(ManagedSelector.java:918)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.processTask(ThreadPoolExecutor.java:1187)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err:   ... 1 more

My 2nd execution crashed (I killed the application before)

10/27 08:56:11: Launching 'mobile' on HUAWEI ANE-LX1.
App restart successful without requiring a re-install.
$ adb shell am start -n "com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 31021 on device 'huawei-ane_lx1-9WV7N18928005405'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#256
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#256
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#0
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#0
I/t.myapplicatio: QarthPatchMonintor::Init
    QarthPatchMonintor::StartWatch
I/t.myapplicatio: QarthPatchMonintor::WatchPackage: /data/hotpatch/fwkhotpatch/
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/com.pezcraft.myapplication
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/all
    QarthPatchMonintor::Run
I/t.myapplicatio: QarthPatchMonintor::Reading
    QarthPatchMonintor::CheckNotifyEvent
    QarthPatchMonintor::CheckNotifyEvent before read
I/AwareBitmapCacher: init processName:com.pezcraft.myapplication pid=31021 uid=10285
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: Runnable thread started.
D/IMonitor: Load library imonitor_jni
E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
W/ZrHung.AppEyeUiProbe: Failed to get config from zrhung
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile@7b0d00c
V/HwPolicyFactory: : success to get AllImpl object and return....
V/ActivityThread: callActivityOnCreate
W/t.myapplicatio: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
I/HwApsImpl: APS: new HwApsImpl created
V/HwWidgetFactory: : successes to get AllImpl object and return....
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/t.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@23f6ee6,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@2039372,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
D/TextView: get Display Panel Type is : 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@aaec91f,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@a80d83b,com.pezcraft.heartrateonstream.IntroActivity@e7f14a4
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
W/t.myapplicatio: Accessing hidden field Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; (light greylist, reflection)
D/ActivityThread: add activity client record, r= ActivityRecord{40413b3 token=android.os.BinderProxy@44787e3 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@44787e3
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@32f1d70
D/ZrHung.AppEyeUiProbe: notify runnable to start.
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
V/ActivityThread: callActivityOnCreate
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/System.err: Defaulting Uptime to NOIMPL due to (java.lang.UnsupportedOperationException) Implementation not available in this environment
W/System.err: 2021-10-27 08:56:09.512:INFO::main: Logging initialized @-1ms to org.eclipse.jetty.util.log.StdErrLog
D/ActivityThread: add activity client record, r= ActivityRecord{59387ef token=android.os.BinderProxy@32f1d70 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.MobileMainActivity}} token= android.os.BinderProxy@32f1d70
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
D/OpenGLRenderer: Skia GL Pipeline
I/HwSecImmHelper: mSecurityInputMethodService is null
D/HwAppInnerBoostImpl: set config for com.pezcraft.myapplication BOOST_FLAG=false REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
D/OpenGLRenderer:   HWUI Binary is  enabled
I/System.out: Connecting to: ws://192.168.1.102:4444.
I/HiTouch_HiTouchSensor: enabledInPad = false,isPcCastMode = false
D/HiTouch_PressGestureDetector: onAttached, package=com.pezcraft.myapplication, windowType=1, mHiTouchRestricted=false
D/HeartRateOnStream: subs-before-remove-com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removing...)com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: inside-remove (removed)com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    subs-after-remove-com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/AndroidRuntime: Shutting down VM
W/t.myapplicatio: Accessing hidden method Lcom/msic/qarth/PatchStore;->createDisableExceptionQarthFile(Ljava/lang/Throwable;)Z (blacklist, JNI)
E/t.myapplicatio: [qarth_debug:]  get PatchStore::createDisableExceptionQarthFile method fail.
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.pezcraft.myapplication, PID: 31021
    java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getVisibility()' on a null object reference
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3416)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3415)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1944)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1633)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7943)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
        at android.view.Choreographer.doCallbacks(Choreographer.java:893)
        at android.view.Choreographer.doFrame(Choreographer.java:812)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
        at android.os.Handler.handleCallback(Handler.java:907)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:216)
        at android.app.ActivityThread.main(ActivityThread.java:7625)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
I/Process: Sending signal. PID: 31021 SIG: 9

Then I deleted the removeFabOption call of the subs callback. It makes no difference. Also, I removed the whole inapp callback. Still the same.

kabumere commented 3 years ago

Hey @Pezcraft,

1) Your first log dump ends in a crash. What is causing that crash? Why did you have to 'kill the application'? 2) You say of the first execution it worked, but from the logs that doesn't seem to be the case. I see subs-before-remove and inside-remove (removing...) but I DON'T see inside-remove (removed) or subs-after-remove in that first execution log dump. This would lead me to believe that the first callback never finished invoking before the unrelated crash. 3) In that 2nd execution log dump, I see:

D/HeartRateOnStream: subs-before-remove-com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removing...)com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: inside-remove (removed)com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    subs-after-remove-com.nambimobile.widgets.efab.FabOption{61d87b6 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}

This seems to show that the remove FabOption call completed successfully (not how the logs for inside-remove (removed) and subs-after-remove were printed). Here, it seems like something else caused the crash that you're seeing. If the library was causing the crash, those log statements would not be executed (the Exception would have propagated up before hand).

Ultimately, I can't reproduce this error and I think it's an issue with your code. But for one last test to try to narrow it down, change removeFabOption to this:

private void removeFabOption(FabOption fabOption) {
    Log.d(DEBUG, "Before accessing ExpandableFabLayout...");
    // Notice here we access the list of FabOptions, but we no longer remove anything. We just simply access the list.
    expandableFabLayout.getPortraitConfiguration().getFabOptions();
    Log.d(DEBUG, "After accessing ExpandableFabLayout...");
}

Basically, we will keep everything the same and access the fabOptions list, but not remove anything from it. Do you still get the crash with everything else being the same?

Pezcraft commented 3 years ago

No, I just killed the app to be sure, that it gets restarted completely.

It works without remove...

10/28 12:44:32: Launching 'mobile' on HUAWEI ANE-LX1.
App restart successful without requiring a re-install.
$ adb shell am start -n "com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 30583 on device 'huawei-ane_lx1-9WV7N18928005405'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#256
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#256
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#0
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#0
I/t.myapplicatio: QarthPatchMonintor::Init
I/t.myapplicatio: QarthPatchMonintor::StartWatch
    QarthPatchMonintor::WatchPackage: /data/hotpatch/fwkhotpatch/
I/t.myapplicatio: QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/com.pezcraft.myapplication
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/all
    QarthPatchMonintor::Run
I/t.myapplicatio: QarthPatchMonintor::Reading
    QarthPatchMonintor::CheckNotifyEvent
    QarthPatchMonintor::CheckNotifyEvent before read
I/AwareBitmapCacher: init processName:com.pezcraft.myapplication pid=30583 uid=10285
E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: Runnable thread started.
D/IMonitor: Load library imonitor_jni
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
W/ZrHung.AppEyeUiProbe: Failed to get config from zrhung
E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile@342d3f4
V/HwPolicyFactory: : success to get AllImpl object and return....
V/ActivityThread: callActivityOnCreate
W/t.myapplicatio: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
I/HwApsImpl: APS: new HwApsImpl created
V/HwWidgetFactory: : successes to get AllImpl object and return....
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/t.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@e1f8d8e,com.pezcraft.heartrateonstream.IntroActivity@500ad8c
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@30af49a,com.pezcraft.heartrateonstream.IntroActivity@500ad8c
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
D/TextView: get Display Panel Type is : 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@eec2fa7,com.pezcraft.heartrateonstream.IntroActivity@500ad8c
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@fa21f43,com.pezcraft.heartrateonstream.IntroActivity@500ad8c
    initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
W/t.myapplicatio: Accessing hidden field Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; (light greylist, reflection)
D/ActivityThread: add activity client record, r= ActivityRecord{41633bb token=android.os.BinderProxy@8c871eb {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@8c871eb
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@ed930d8
D/ZrHung.AppEyeUiProbe: notify runnable to start.
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
V/ActivityThread: callActivityOnCreate
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
D/ActivityThread: add activity client record, r= ActivityRecord{4ebeb87 token=android.os.BinderProxy@ed930d8 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.MobileMainActivity}} token= android.os.BinderProxy@ed930d8
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/OpenGLRenderer: Skia GL Pipeline
I/HwSecImmHelper: mSecurityInputMethodService is null
D/HwAppInnerBoostImpl: set config for com.pezcraft.myapplication BOOST_FLAG=false REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
D/OpenGLRenderer:   HWUI Binary is  enabled
I/HiTouch_HiTouchSensor: enabledInPad = false,isPcCastMode = false
D/HiTouch_PressGestureDetector: onAttached, package=com.pezcraft.myapplication, windowType=1, mHiTouchRestricted=false
D/HeartRateOnStream: subs-before-remove-com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removing...)com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: inside-remove (removed)com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: subs-after-remove-com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: inapp-before-remove-com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removing...)com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-remove (removed)com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
D/HeartRateOnStream: inapp-after-remove-com.nambimobile.widgets.efab.FabOption{fa6a549 GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=true, mIsFloating=false
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/iGraphics: [0020080c] pn: com.pezcraft.myapplication, p: 30583
    [0030080c] no spt app: com.pezcraft.myapplication
I/OpenGLRenderer: Initialized EGL, version 1.4, mEglDisplay 0x1
D/OpenGLRenderer: Swap behavior 2
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
I/ViewRootImpl: jank_removeInvalidNode jank list is null
W/InputMethodManager: startInputReason = 1
W/InputMethodManager: startInputReason = 5
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
D/ActivityThread: Remove activity client record, r= ActivityRecord{41633bb token=android.os.BinderProxy@8c871eb {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@8c871eb
D/ZrHung.AppEyeUiProbe: Current Activity:true
D/AwareBitmapCacher: handleInit switch not opened pid=30583

It has to do something with remove. And yes, there is veeery weird stuff happening. I am running out of ideas. Should I send you my full project?

kabumere commented 3 years ago

@Pezcraft and it works correctly outside of the callbacks right?

Sure, post your code to github and I'll try to get around to playing with it within the next week.

Pezcraft commented 3 years ago

Yes, for example, it works inside my fab onclick listeners. Today I tried to do the opposite and add the getPremium fabOption instead of removing it (would be the better way anyway)

private void addFabOption(FabOption fabOption2) {
    Log.d(DEBUG, "inside-add (adding...)" + fabOption.toString());
//        expandableFabLayout.removeAllViews(); //by the way, same exception
    expandableFabLayout.addViews(fabOption);
    Log.d(DEBUG, "inside-add (added)" + fabOption.toString());  //stops before this line
}

But again, the code stops executing after addViews (but does not crash). My last log output is simply not executed and my fabOption was not added.

10/31 22:06:18: Launching 'mobile' on Physical Device.
Install successfully finished in 2 s 982 ms.
$ adb shell am start -n "com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 11051 on device 'huawei-ane_lx1-9WV7N18928005405'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/t.myapplicatio: Late-enabling -Xcheck:jni
I/t.myapplicatio: Reinit property: dalvik.vm.checkjni= false
D/ZrHung.AppEyeUiProbe: AppEyeUIP created.
D/ActivityThread: Attach thread to application
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#256
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#256
I/HwApiCacheMangerEx: apicache path=/storage/emulated/0 state=mounted key=com.pezcraft.myapplication#10285#0
    apicache path=/storage/6434-3831 state=mounted key=com.pezcraft.myapplication#10285#0
I/t.myapplicatio: QarthPatchMonintor::Init
I/t.myapplicatio: QarthPatchMonintor::StartWatch
    QarthPatchMonintor::WatchPackage: /data/hotpatch/fwkhotpatch/
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/com.pezcraft.myapplication
    QarthPatchMonintor::CheckAndWatchPatch: /data/hotpatch/fwkhotpatch/all
    QarthPatchMonintor::Run
I/t.myapplicatio: QarthPatchMonintor::Reading
I/t.myapplicatio: QarthPatchMonintor::CheckNotifyEvent
    QarthPatchMonintor::CheckNotifyEvent before read
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: Runnable thread started.
D/IMonitor: Load library imonitor_jni
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0102]
W/ZrHung.AppEyeUiProbe: Failed to get config from zrhung
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
I/AwareBitmapCacher: init processName:com.pezcraft.myapplication pid=11051 uid=10285
E/MemoryLeakMonitorManager: MemoryLeakMonitor.jar is not exist!
E/AwareLog: AtomicFileUtils: readFileLines file not exist: android.util.AtomicFile@75eb504
V/HwPolicyFactory: : success to get AllImpl object and return....
V/ActivityThread: callActivityOnCreate
W/t.myapplicatio: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
W/t.myapplicatio: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
W/t.myapplicatio: Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
    Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
I/HwApsImpl: APS: new HwApsImpl created
V/HwWidgetFactory: : successes to get AllImpl object and return....
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate; (light greylist, linking)
W/t.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/t.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@9492a1e,com.pezcraft.heartrateonstream.IntroActivity@75a09c
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@d9ca2a,com.pezcraft.heartrateonstream.IntroActivity@75a09c
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
D/TextView: get Display Panel Type is : 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@4d592f7,com.pezcraft.heartrateonstream.IntroActivity@75a09c
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
I/FLTAG_FM: loadFeature class:com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
I/FLTAG_SFM: getRequireClassLoader() succ ! className: com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
D/FeatureFactory: loadFeature() : com.huawei.featurelayer.systemfeature.HwWidget.IHwSplineOverScrollerEx
    loadFeature() new IHwSplineOverScrollerEx()
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl paras: android.widget.OverScroller$SplineOverScroller@466793,com.pezcraft.heartrateonstream.IntroActivity@75a09c
D/HwSplineOverScrollerExImpl: initSplineOverScrollerImpl: mScrollerVelocity is 0, value is 0
W/t.myapplicatio: Accessing hidden field Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate; (light greylist, reflection)
D/ActivityThread: add activity client record, r= ActivityRecord{151360b token=android.os.BinderProxy@539d83b {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@539d83b
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
D/ZrHung.AppEyeUiProbe: notify runnable to start.
V/ActivityThread: Skipping new config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7}, config:{1.0 232mcc12mnc [de_AT] ldltr sw360dp w360dp h686dp 480dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=Rect(0, 90 - 1080, 2150) mWindowingMode=fullscreen mActivityType=undefined} nonFullScreen=0 suim:1 s.7} for app:com.pezcraft.myapplication
V/ActivityThread: callActivityOnCreate
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=0, mNavBarShow=false, mIsFloating=false
I/HwPhoneWindow: updateLayoutParamsColor true mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=false, mIsFloating=false
D/ActivityThread: add activity client record, r= ActivityRecord{b87b6d7 token=android.os.BinderProxy@58d8ce8 {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.MobileMainActivity}} token= android.os.BinderProxy@58d8ce8
D/ZrHung.AppEyeUiProbe: notify runnable to start.
E/: [ZeroHung]zrhung_get_config: Get config failed for wp[0x0008]
D/OpenGLRenderer: Skia GL Pipeline
I/HwSecImmHelper: mSecurityInputMethodService is null
D/HwAppInnerBoostImpl: set config for com.pezcraft.myapplication BOOST_FLAG=false REPORT_DURATION_CLICK=1000 REPORT_TIMES_CLICK=3 REPORT_DURATION_SLIDE=5000 REPORT_TIMES_SLIDE=16
D/OpenGLRenderer:   HWUI Binary is  enabled
I/HiTouch_HiTouchSensor: enabledInPad = false,isPcCastMode = false
D/HiTouch_PressGestureDetector: onAttached, package=com.pezcraft.myapplication, windowType=1, mHiTouchRestricted=false
D/HeartRateOnStream: subs-before-add-com.nambimobile.widgets.efab.FabOption{e1ffade GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
    inside-add (adding...)com.nambimobile.widgets.efab.FabOption{e1ffade GFED..C.. ......I. 0,0-0,0 #7f0900cb app:id/fabOptionPremium}
I/HwPhoneWindow: updateLayoutParamsColor false mSpecialSet=false, mForcedNavigationBarColor=false, navigationBarColor=ff000000, mNavBarShow=true, mIsFloating=false
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/iGraphics: [0020080c] pn: com.pezcraft.myapplication, p: 11051
    [0030080c] no spt app: com.pezcraft.myapplication
I/OpenGLRenderer: Initialized EGL, version 1.4, mEglDisplay 0x1
D/OpenGLRenderer: Swap behavior 2
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
W/InputMethodManager: startInputReason = 1
I/ViewRootImpl: jank_removeInvalidNode jank list is null
W/InputMethodManager: startInputReason = 5
D/ZrHung.AppEyeUiProbe: notify runnable to start.
D/ZrHung.AppEyeUiProbe: stop checker.
D/ActivityThread: Remove activity client record, r= ActivityRecord{151360b token=android.os.BinderProxy@539d83b {com.pezcraft.myapplication/com.pezcraft.heartrateonstream.IntroActivity}} token= android.os.BinderProxy@539d83b
D/ZrHung.AppEyeUiProbe: Current Activity:true
D/AwareBitmapCacher: handleInit switch not opened pid=11051
V/InputMethodManager: Reporting focus gain, without startInput

I invited you to my repository.

kabumere commented 3 years ago

@Pezcraft,

Please extract only the logic causing the issue into its own smaller project.

So just put together a dummy project where the only dependencies are the ExpandableFab library and the Google Play Billing Library. Then ensure you can reproduce the issue on your device, then upload that smaller app.

I don't have a Huawei to use, which it looks like you're using, but I'll see if I can reproduce it on the devices I do have.

EDIT: Actually, speaking of which, have you tested your app in an Emulator to be sure that the issue isn't specific to Huawei devices?

Pezcraft commented 3 years ago

@kabumere

omg, I feel so stupid. You were right, I have kind of switched activities. I found the bug. The bug was caused by another bug. But let's talk about why I was not able to remove the fabOption. The bug occurred, because I recreated my activity this.recreate(); inside handlePurchases(). And because I am calling an async task inside an async task, the library wasn't able to remove the fabOption since the activity got recreated before. But the async task inside the async task isn't really a problem, because I recreated the activity just by accident. The recreation shouldn't be executed anyway. That was my bug. So 2 bugs. Ok, it's complicated. So in the end, I can say: Don't recreate an activity inside asynchronous tasks. Or even better, don't manipulate the GUI inside asynchronous tasks. One more question... I think it's better to remove/add my fabOption when the user clicks the main fab button the first time, so I can avoid manipulating my GUI inside an asynchronous task. Is this possible?

billingClient.queryPurchasesAsync(SkuType.SUBS, (billingResult1, queryPurchasesSubs) -> {
                        if (queryPurchasesSubs.size() > 0){
                            handlePurchases(queryPurchasesSubs);
                        } else {
                            //if no item in purchase list means no, cancelled, or paused subscription
                            prefManager.setPremium(false);
                        }

                        billingClient.queryPurchasesAsync(SkuType.INAPP, (billingResult2, queryPurchasesOnetime) -> {
                            if (queryPurchasesOnetime.size() > 0){
                                handlePurchases(queryPurchasesOnetime);
                            } else {
                                //if no item in purchase list means no, cancelled, or paused subscription
                                prefManager.setPremium(false);
                            }
                            addFabOption(fabOption);
                        });
                    });
kabumere commented 3 years ago

Hey @Pezcraft,

I'm glad you found the cause of the bug! No need to feel stupid, mistakes like that happen to the best of us.

Removing the FabOption based off some boolean is simple and shouldn't be noticeable by users. You can do something like the following to achieve this (coed:

// Have this boolean set in your 'queryPurchasesAsync' callbacks.
val showPremiumOption = false

override fun onCreate(savedInstanceState: Bundle?) {
  val expandableFabLayout = findViewById<ExpandableFabLayout>(R.id.expandable_fab_layout)
  val premiumFabOption = findViewById<FabOption>(R.id.premium_option)

  val expandableFab = view.findViewById<ExpandableFab>(R.id.expandable_fab).setOnClickListener {
    if(!showPremiumOption && premiumFabOption .parent != null) {
      expandableFabLayout.portraitConfiguration.fabOptions.remove(premiumFabOption )
    }
  }
}

This will remove premiumFabOption from the list only if showPremiumOption is false and premiumFabOption has a parent. The 2nd condition checking the parent is important - once the FabOption is removed the first time, it will no longer have a parent, so we won't call remove every single time the ExpandableFab is clicked afterwards (however calling remove with a FabOption that is not in the list is safe, it's just an unnecessary extra call that can be avoided).


If you want to be able to add back in the premiumFabOption using similar logic, you can implement the below code (however this option has a caveat: see 'NOTE' below):

// Have this boolean set in your 'queryPurchasesAsync' callbacks.
val showPremiumOption = false

override fun onCreate(savedInstanceState: Bundle?) {
  val expandableFabLayout = findViewById<ExpandableFabLayout>(R.id.expandable_fab_layout)
  val premiumFabOption = findViewById<FabOption>(R.id.premium_option)

  val expandableFab = view.findViewById<ExpandableFab>(R.id.expandable_fab).setOnClickListener {
    when {
      showPremiumOption && premiumFabOption.parent == null -> {
        expandableFabLayout.addView(premiumFabOption)
      }
      !showPremiumOption && premiumFabOption.parent != null -> {
        expandableFabLayout.portraitConfiguration.fabOptions.remove(premiumFabOption)
      }
    }
  }
}

This does the same as the first code block, except it has an additional conditional that will add back in the FabOption if showPremiumOption is true and premiumFabOption does not have a parent.

NOTE: The ExpandableFab button's default onClick behavior is executed before any custom onClick behavior set by the client. What this means is that the ExpandableFab begins opening or closing before executing your call to remove/add the FabOption in question.

Because of this, removing a FabOption while the ExpandableFab is in the middle of opening or closing works seamlessly. However, adding a FabOption as the ExpandableFab is opening can look weird, as it will show before it's suppose to (but only during the first time. All other times it will show when the list gets to its index correctly). There are ways to make adding the FabOption in this scenario look cleaner, but it likely won't be as clean of a solution as the codeblocks above.

kabumere commented 3 years ago

Answering this also made me think of some new features for the library:

Right now, you can remove a FabOption by removing it from the list on the OrientationConfiguration, but you can't properly remove a FabOption from the ExpandableFabLayout directly.

Likewise, you can add a FabOption to the layout using addView or addViews on the ExpandableFabLayout directly, but you can't add them to the list on the OrientationConfiguration mentioned above.

I plan to add to the next release:

  1. Ability to add one or more FabOptions to an OrientationConfiguration's list of FabOptions and have it also add to the ExpandableFabLayout.
  2. Ability to remove one or more FabOptions from the ExpandableFabLayout directly, and have it correctly reflect in the lists held by OrientationConfigurations.
  3. Ability to properly remove Overlays and ExpandableFabs from the ExpandableFabLayout directly and have it reflect on the correct OrientationConfiguration as well (will need to update documentation on removeAllViews since I purposefully didn't allow this before).
kabumere commented 3 years ago

Hey @Pezcraft,

Did the above solution answer your question?

Pezcraft commented 3 years ago

@kabumere Yes, it did. Thank you very much :)