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

Commit f46864e2 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

[Floaty] Fix Floaty window addition logic

This CL contains 3 bugfixes:
1. Top-UI refactor was not respected for the setRequestTopUi(true) call
2. The addWindow function is changed to be uninterruptible
   Previously, it could happen that it was interrupted during the
   requestTopUi suspending function. This would leave the class in a
   state of root being initialized but not added to WindowManager.
3. root cannot be reset to null anymore without windowManager.removeView
   being called. This could have led to a bug of multiple root views
   being added without them being removed again.

Bug: 414714786
Flag: com.android.systemui.shared.enable_lpp_assist_invocation_effect
Test: TopLevelWindowEffectsTest
Change-Id: I634f21498ce55808e6ed4930f5cea34867347775
parent a3352e31
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.view.WindowManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyevent.data.repository.fakeKeyEventRepository
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
@@ -44,7 +45,6 @@ import com.android.systemui.topwindoweffects.ui.viewmodel.SqueezeEffectViewModel
import java.util.Optional
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.test.StandardTestDispatcher
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -74,7 +74,7 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
        Kosmos.Fixture {
            TopLevelWindowEffects(
                context = mContext,
                mainDispatcher = StandardTestDispatcher(testScope.testScheduler),
                mainExecutor = kosmos.fakeExecutor,
                topLevelWindowEffectsScope = testScope.backgroundScope,
                windowManager = windowManager,
                viewModelFactory = viewModelFactory,
@@ -258,6 +258,7 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
        if (TopUiControllerRefactor.isEnabled) {
            verify(topUiController, mode).setRequestTopUi(true, TopLevelWindowEffects.TAG)
        } else {
            kosmos.fakeExecutor.runAllReady()
            verify(kosmos.notificationShadeWindowController, mode)
                .setRequestTopUi(true, TopLevelWindowEffects.TAG)
        }
+17 −14
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.topwindoweffects

import android.content.Context
import android.graphics.PixelFormat
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.WindowInsets
@@ -38,20 +39,19 @@ import com.android.systemui.topwindoweffects.ui.compose.EffectsWindowRoot
import com.android.systemui.topwindoweffects.ui.viewmodel.SqueezeEffectViewModel
import com.android.wm.shell.appzoomout.AppZoomOut
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@SysUISingleton
class TopLevelWindowEffects
@Inject
constructor(
    @Application private val context: Context,
    @Main private val mainDispatcher: CoroutineDispatcher,
    @Main private val mainExecutor: Executor,
    @TopLevelWindowEffectsThread private val topLevelWindowEffectsScope: CoroutineScope,
    private val windowManager: WindowManager,
    private val squeezeEffectInteractor: SqueezeEffectInteractor,
@@ -92,7 +92,7 @@ constructor(
        }
    }

    private suspend fun addWindow(
    private fun addWindow(
        @DrawableRes topRoundedCornerId: Int,
        @DrawableRes bottomRoundedCornerId: Int,
        physicalPixelDisplaySizeRatio: Float,
@@ -102,6 +102,7 @@ constructor(
        }

        if (root != null) {
            Log.i(TAG, "addWindow: remove previous window")
            removeWindow()
        }

@@ -120,29 +121,31 @@ constructor(
                .apply { visibility = View.GONE }

        root?.let { rootView ->
            runOnMainThread { notificationShadeWindowController.setRequestTopUi(true, TAG) }
            setRequestTopUi(true)
            windowManager.addView(rootView, getWindowManagerLayoutParams())
            rootView.post { rootView.visibility = View.VISIBLE }
        }
    }

    private suspend fun removeWindow() {
        if (root?.isAttachedToWindow == true) {
    private fun removeWindow() {
        if (root != null) {
            windowManager.removeView(root)
            root = null
        }

        root = null
        isInvocationEffectHappening = false

        setRequestTopUi(false)
    }

    private fun setRequestTopUi(requestTopUi: Boolean) {
        if (TopUiControllerRefactor.isEnabled) {
            topUiController.setRequestTopUi(false, TAG)
            topUiController.setRequestTopUi(requestTopUi, TAG)
        } else {
            runOnMainThread { notificationShadeWindowController.setRequestTopUi(false, TAG) }
            mainExecutor.execute {
                notificationShadeWindowController.setRequestTopUi(requestTopUi, TAG)
            }
        }

    private suspend fun runOnMainThread(block: () -> Unit) {
        withContext(mainDispatcher) { block() }
    }

    private fun getWindowManagerLayoutParams(): WindowManager.LayoutParams {