Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5718c45 authored by Lucas Silva's avatar Lucas Silva
Browse files

Fix widget view memory leak on hub

We currently don't remove listeners from AppWidgetHost, meaning that the
AppWidgetHostViews leak after the hub has been closed.

This change ensures that we correctly remove listeners when the hub is
closed.

Fixes: 406044666
Test: atest CommunalAppWidgetViewModelTest
Flag: EXEMPT bugfix
Change-Id: I0b27572ff7e24a803d40058bfbf66be449022654
parent 71d19085
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -140,6 +140,30 @@ class CommunalAppWidgetViewModelTest(flags: FlagsParameterization) : SysuiTestCa
                )
        }

    @Test
    fun removeListener() =
        kosmos.runTest {
            val listener = mock<AppWidgetHostListener>()

            underTest.setListener(123, listener)
            runAll()
            underTest.removeListener(123)

            verify(appWidgetHost).removeListener(123)
        }

    @Test
    fun removeListener_HSUM() =
        kosmos.runTest {
            fakeGlanceableHubMultiUserHelper.setIsInHeadlessSystemUser(true)
            val listener = mock<AppWidgetHostListener>()

            underTest.setListener(123, listener)
            runAll()

            verify(listener).updateAppWidget(any())
        }

    private fun Kosmos.runAll() {
        runCurrent()
        fakeExecutor.runAllReady()
+5 −1
Original line number Diff line number Diff line
@@ -115,7 +115,11 @@ constructor(
            },
            modifier = modifier,
            // For reusing composition in lazy lists.
            onReset = {},
            onReset = { view ->
                viewModel.removeListener(model.appWidgetId)
                view.setTag(LISTENER_TAG, null)
            },
            onRelease = { view -> viewModel.removeListener(model.appWidgetId) },
        )
    }

+10 −0
Original line number Diff line number Diff line
@@ -69,6 +69,16 @@ constructor(
        requests.trySend(UpdateSize(size, view))
    }

    fun removeListener(appWidgetId: Int) {
        if (
            multiUserHelper.glanceableHubHsumFlagEnabled && multiUserHelper.isInHeadlessSystemUser()
        ) {
            glanceableHubWidgetManagerLazy.get().removeAppWidgetHostListener(appWidgetId)
        } else {
            appWidgetHostLazy.get().removeListener(appWidgetId)
        }
    }

    override suspend fun onActivated(): Nothing {
        coroutineScopeTraced("$TAG#onActivated") {
            requests.receiveAsFlow().collect { request ->
+5 −0
Original line number Diff line number Diff line
@@ -104,6 +104,11 @@ constructor(
            service.setAppWidgetHostListener(appWidgetId, createIAppWidgetHostListener(listener))
        }

    /** Requests the foreground user to remove the listener for a given app widget. */
    fun removeAppWidgetHostListener(appWidgetId: Int) = runOnService { service ->
        service.removeAppWidgetHostListener(appWidgetId)
    }

    /** Requests the foreground user to add a widget. */
    fun addWidget(
        provider: ComponentName,
+14 −0
Original line number Diff line number Diff line
@@ -134,6 +134,10 @@ constructor(
        appWidgetHost.setListener(appWidgetId, createListener(listener))
    }

    private fun removeAppWidgetHostListenerInternal(appWidgetId: Int) {
        appWidgetHost.removeListener(appWidgetId)
    }

    private fun addWidgetInternal(
        provider: ComponentName?,
        user: UserHandle?,
@@ -290,6 +294,16 @@ constructor(
            }
        }

        override fun removeAppWidgetHostListener(appWidgetId: Int) {
            val iden = clearCallingIdentity()

            try {
                removeAppWidgetHostListenerInternal(appWidgetId)
            } finally {
                restoreCallingIdentity(iden)
            }
        }

        override fun addWidget(
            provider: ComponentName?,
            user: UserHandle?,
Loading