Status Update
Comments
ga...@google.com <ga...@google.com> #2
class FixDrawerLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : DrawerLayout(context, attrs) {
fun registerToFragmentLifecycle(fragment: Fragment) {
fragment.viewLifecycleOwner.launchOnLifecycleDestroy {
super.onDetachedFromWindow()
}
}
}
du...@gener8ads.com <du...@gener8ads.com> #3
With markdown the same:
I have a project on SingleActivity. And in manifest android:enableOnBackInvokedCallback="true". I have a Root Fragment with a toolbar to which I attach a DrawerLayout.
<!-- XML Root Fragment -->
<androidx.drawerlayout.widget.DrawerLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.MaterialToolbar />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.core.widget.NestedScrollView
android:layout_gravity="start">
</androidx.drawerlayout.widget.DrawerLayout>
On button click in DrawerLayout I change RootFragment and lose all View in this Xml after onDestroyView. I don't call close() or closeDrawer() because I need the old state when I return to this fragment. But!
The DrawerLayout calls onDetachedFromWindow() which calls updateBackInvokedCallbackState() where ViewCompat.isAttachedToWindow(this) returns true and all the following condition is also true.
boolean shouldBeRegistered = visibleDrawer != null
&& currentDispatcher != null
&& getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED
&& ViewCompat.isAttachedToWindow(this);
As a consequence, the following code cannot be executed:
} else if (!shouldBeRegistered && mBackInvokedDispatcher != null) {
Api33Impl.tryUnregisterOnBackInvokedCallback(
mBackInvokedDispatcher, mBackInvokedCallback);
mBackInvokedDispatcher = null;
}
Where mBackInvokedDispatcher != null is true, and shouldBeRegistered is true (but !shouldBeRegistered is false).
Consequently, my mechanical back button or slide (back gesture) is blocked and not called on a new Root fragment when the DrawerLayout is Destroyed.
<!-- new Root fragment -->
<androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.appbar.MaterialToolbar />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
There may be a workaround, but that's not all. The fact is that LeakCanary reacts to this error, which claims that after registerOnBackInvokedCallback and not called tryUnregisterOnBackInvokedCallback, a memory leak occurs.
fast fix: android:enableOnBackInvokedCallback="false" or downgrade DrawerLayout to 1.1.1 or
wa...@google.com <wa...@google.com> #4
What I've seen is that when I show a new fragment as a result of a drawer layout navigation view being selected, back gestures break with `enableOnBackInvokedCallback` on stop working - and I saw the same else if block you mentioned above _not_ get called and result in stale/stuck back handlers consuming the gestures in this scenario.
I was able to delay showing the fragment until after the drawer layout closed, and the issue did not exist there.
The odd thing is - when I try out older drawer layout versions, the bug still exists. So maybe it's something deeper? I'm working to get a sample app setup to demo this, will circle back soon but wanted to add my current observations.
wa...@google.com <wa...@google.com> #5
after the drawer layout closed
According to my requirements, it should not close, since there is a screen animation where you can see that it is open. So the hot fix only helps through custom view.
fun registerToFragmentLifecycle(fragment: Fragment) {
fragment.viewLifecycleOwner.launchOnLifecycleDestroy {
super.onDetachedFromWindow()
}
}
du...@gener8ads.com <du...@gener8ads.com> #6
related to `launchOnLifecycleDestroy` - what is that method? I don't see it anywhere in my repo/online. Is that a custom API? Would be curious what that does!
du...@gener8ads.com <du...@gener8ads.com> #7
Here's my sample app btw -
Again, I'm not sure if our issues are exactly the same, but I get "stuck" not being able to swipe back between fragments after navigating to a fragment starting from a menu item being selected in a Drawer Layout - so it sounds similar...
Description
Problem you encountered:
We have encountered a critical issue with our integration with the Google Data Portability API. When a user authorizes us to retrieve their Google Data via the Portability API, this prevents that same user from being able to use Google as a single sign-on provider.
What you expected to happen:
The user should be able to use Google as an SSO provider, i.e. the user should allowed to authorize us to fetch their
email
andprofile
information from Google; after they have granted us time-based access to their Data Portability scopes.Steps to reproduce:
Generate a google oAuth clientID
Use the clientID to execute a "Sign in with Google" request
Use the same clientID to execute a "Google DPA Authorization" request
Without calling the
authorization:reset
method on the Google Data Portability API, attempt a second "Sign in with Google" requestGoogle renders an error: Access blocked: authorisation error
Other information (such as workarounds you tried and documentation consulted):
Are we expected to be using separate oAuth clientIDs for Sign in with Google & for our Google DPA Integration? There is nothing I've found supporting this to be the case across any of the documentation I've reviewed. By experimentation, it would seem that the opposite is meant to be the case, since if we take the above situation, but invoke
authorization:reset
on the user after exporting their Google Data Portability data. The scopes for the Data Portability API are revoked in theirhttps://myaccount.google.com/connections
page, but the granted scopes for Sign in remain in place.