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

Commit bebce12d authored by Shan Huang's avatar Shan Huang Committed by Android (Google) Code Review
Browse files

Merge "Use SyncRtSurfaceTransactionApplier to apply blur." into main

parents d2f5deb3 065435dc
Loading
Loading
Loading
Loading
+50 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view;

import android.annotation.SuppressLint;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.SurfaceControl.Transaction;
@@ -39,6 +40,9 @@ public class SyncRtSurfaceTransactionApplier {
    public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
    public static final int FLAG_VISIBILITY = 1 << 6;
    public static final int FLAG_TRANSACTION = 1 << 7;
    public static final int FLAG_EARLY_WAKEUP_START = 1 << 8;
    public static final int FLAG_EARLY_WAKEUP_END = 1 << 9;
    public static final int FLAG_OPAQUE = 1 << 10;

    private SurfaceControl mTargetSc;
    private final ViewRootImpl mTargetViewRootImpl;
@@ -99,6 +103,7 @@ public class SyncRtSurfaceTransactionApplier {
        }
    }

    @SuppressLint("MissingPermission")
    public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
        if ((params.flags & FLAG_TRANSACTION) != 0) {
            t.merge(params.mergeTransaction);
@@ -129,6 +134,15 @@ public class SyncRtSurfaceTransactionApplier {
                t.hide(params.surface);
            }
        }
        if ((params.flags & FLAG_EARLY_WAKEUP_START) != 0) {
            t.setEarlyWakeupStart();
        }
        if ((params.flags & FLAG_EARLY_WAKEUP_END) != 0) {
            t.setEarlyWakeupEnd();
        }
        if ((params.flags & FLAG_OPAQUE) != 0) {
            t.setOpaque(params.surface, params.opaque);
        }
    }

    /**
@@ -172,6 +186,7 @@ public class SyncRtSurfaceTransactionApplier {
            Rect windowCrop;
            int layer;
            boolean visible;
            boolean opaque;
            Transaction mergeTransaction;

            /**
@@ -262,18 +277,49 @@ public class SyncRtSurfaceTransactionApplier {
                return this;
            }

            /**
             * Provides a hint to SurfaceFlinger to change its offset so that SurfaceFlinger
             * wakes up earlier to compose surfaces.
             * @return this Builder
             */
            public Builder withEarlyWakeupStart() {
                flags |= FLAG_EARLY_WAKEUP_START;
                return this;
            }

            /**
             * Removes the early wake up hint set by earlyWakeupStart.
             * @return this Builder
             */
            public Builder withEarlyWakeupEnd() {
                flags |= FLAG_EARLY_WAKEUP_END;
                return this;
            }

            /**
             * @param opaque Indicates weather the surface must be considered opaque.
             * @return this Builder
             */
            public Builder withOpaque(boolean opaque) {
                this.opaque = opaque;
                flags |= FLAG_OPAQUE;
                return this;
            }

            /**
             * @return a new SurfaceParams instance
             */
            public SurfaceParams build() {
                return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
                        cornerRadius, backgroundBlurRadius, visible, mergeTransaction);
                        cornerRadius, backgroundBlurRadius, visible, mergeTransaction,
                        opaque);
            }
        }

        private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
                Rect windowCrop, int layer, float cornerRadius,
                int backgroundBlurRadius, boolean visible, Transaction mergeTransaction) {
                int backgroundBlurRadius, boolean visible,
                Transaction mergeTransaction, boolean opaque) {
            this.flags = params;
            this.surface = surface;
            this.alpha = alpha;
@@ -284,6 +330,7 @@ public class SyncRtSurfaceTransactionApplier {
            this.backgroundBlurRadius = backgroundBlurRadius;
            this.visible = visible;
            this.mergeTransaction = mergeTransaction;
            this.opaque = opaque;
        }

        private final int flags;
@@ -312,5 +359,6 @@ public class SyncRtSurfaceTransactionApplier {
        public final boolean visible;

        public final Transaction mergeTransaction;
        public final boolean opaque;
    }
}
+31 −17
Original line number Diff line number Diff line
@@ -19,22 +19,23 @@ package com.android.systemui.statusbar
import android.content.res.Resources
import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.SyncRtSurfaceTransactionApplier
import android.view.ViewRootImpl
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.ui.transitions.BlurConfig
import com.google.common.truth.Truth.assertThat
import junit.framework.TestCase.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -45,10 +46,13 @@ class BlurUtilsTest : SysuiTestCase() {

    val blurConfig: BlurConfig = BlurConfig(minBlurRadiusPx = 1.0f, maxBlurRadiusPx = 100.0f)
    @Mock lateinit var dumpManager: DumpManager
    @Mock lateinit var transaction: SurfaceControl.Transaction
    @Mock lateinit var crossWindowBlurListeners: CrossWindowBlurListeners
    @Mock lateinit var resources: Resources
    lateinit var blurUtils: TestableBlurUtils
    @Mock lateinit var syncRTTransactionApplier: SyncRtSurfaceTransactionApplier
    @Mock lateinit var transaction: SurfaceControl.Transaction
    @Captor
    private lateinit var captor: ArgumentCaptor<SyncRtSurfaceTransactionApplier.SurfaceParams>
    private lateinit var blurUtils: TestableBlurUtils

    @Before
    fun setup() {
@@ -77,9 +81,10 @@ class BlurUtilsTest : SysuiTestCase() {
        `when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
        `when`(surfaceControl.isValid).thenReturn(true)
        blurUtils.applyBlur(viewRootImpl, radius, true /* opaque */)
        verify(transaction).setBackgroundBlurRadius(eq(surfaceControl), eq(radius))
        verify(transaction).setOpaque(eq(surfaceControl), eq(true))
        verify(transaction).apply()

        verify(syncRTTransactionApplier).scheduleApply(captor.capture())
        assertThat(captor.value.opaque).isTrue()
        assertEquals(radius, captor.value.backgroundBlurRadius)
    }

    @Test
@@ -92,9 +97,10 @@ class BlurUtilsTest : SysuiTestCase() {

        blurUtils.blursEnabled = false
        blurUtils.applyBlur(viewRootImpl, radius, true /* opaque */)
        verify(transaction).setOpaque(eq(surfaceControl), eq(true))
        verify(transaction, never()).setBackgroundBlurRadius(any(), anyInt())
        verify(transaction).apply()

        verify(syncRTTransactionApplier).scheduleApply(captor.capture())
        assertThat(captor.value.opaque).isTrue()
        assertEquals(0 /* unset value */, captor.value.backgroundBlurRadius)
    }

    @Test
@@ -102,24 +108,32 @@ class BlurUtilsTest : SysuiTestCase() {
        val radius = 10
        val surfaceControl = mock(SurfaceControl::class.java)
        val viewRootImpl = mock(ViewRootImpl::class.java)
        val tmpFloatArray = FloatArray(0)
        `when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
        `when`(surfaceControl.isValid).thenReturn(true)
        blurUtils.applyBlur(viewRootImpl, radius, true /* opaque */)

        verify(syncRTTransactionApplier).scheduleApply(captor.capture())
        assertThat(captor.value.opaque).isTrue()
        SyncRtSurfaceTransactionApplier.applyParams(transaction, captor.value, tmpFloatArray)
        verify(transaction).setEarlyWakeupStart()

        clearInvocations(syncRTTransactionApplier)
        clearInvocations(transaction)
        blurUtils.applyBlur(viewRootImpl, 0, true /* opaque */)
        verify(syncRTTransactionApplier).scheduleApply(captor.capture())
        SyncRtSurfaceTransactionApplier.applyParams(transaction, captor.value, tmpFloatArray)
        verify(transaction).setEarlyWakeupEnd()
    }

    inner class TestableBlurUtils : BlurUtils(resources, blurConfig, crossWindowBlurListeners, dumpManager) {
    inner class TestableBlurUtils :
        BlurUtils(resources, blurConfig, crossWindowBlurListeners, dumpManager) {
        var blursEnabled = true
        override val transactionApplier: SyncRtSurfaceTransactionApplier
            get() = syncRTTransactionApplier

        override fun supportsBlursOnWindows(): Boolean {
            return blursEnabled
        }

        override fun createTransaction(): SurfaceControl.Transaction {
            return transaction
        }
    }
}
+88 −65
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import android.util.Log
import android.util.MathUtils
import android.view.CrossWindowBlurListeners
import android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED
import android.view.SurfaceControl
import android.view.SyncRtSurfaceTransactionApplier
import android.view.ViewRootImpl
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
@@ -36,26 +36,35 @@ import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import java.io.PrintWriter
import javax.inject.Inject
import com.android.systemui.keyguard.ui.transitions.BlurConfig
import com.android.systemui.res.R
import java.io.PrintWriter
import javax.inject.Inject

@SysUISingleton
open class BlurUtils @Inject constructor(
open class BlurUtils
@Inject
constructor(
    @Main resources: Resources,
    blurConfig: BlurConfig,
    private val crossWindowBlurListeners: CrossWindowBlurListeners,
    dumpManager: DumpManager
    dumpManager: DumpManager,
) : Dumpable {
    val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius).toFloat()
    val maxBlurRadius = if (Flags.notificationShadeBlur()) {
    val maxBlurRadius =
        if (Flags.notificationShadeBlur()) {
            blurConfig.maxBlurRadiusPx
        } else {
            resources.getDimensionPixelSize(R.dimen.max_window_blur_radius).toFloat()
        }

    private var lastAppliedBlur = 0
    private var lastTargetViewRootImpl: ViewRootImpl? = null
    private var _transactionApplier = SyncRtSurfaceTransactionApplier(null)
    @VisibleForTesting
    open val transactionApplier: SyncRtSurfaceTransactionApplier
        get() = _transactionApplier

    private var earlyWakeupEnabled = false

    /** When this is true, early wakeup flag is not reset on surface flinger when blur drops to 0 */
@@ -65,9 +74,7 @@ open class BlurUtils @Inject constructor(
        dumpManager.registerDumpable(this)
    }

    /**
     * Translates a ratio from 0 to 1 to a blur radius in pixels.
     */
    /** Translates a ratio from 0 to 1 to a blur radius in pixels. */
    fun blurRadiusOfRatio(ratio: Float): Float {
        if (ratio == 0f) {
            return 0f
@@ -75,15 +82,18 @@ open class BlurUtils @Inject constructor(
        return MathUtils.lerp(minBlurRadius, maxBlurRadius, ratio)
    }

    /**
     * Translates a blur radius in pixels to a ratio between 0 to 1.
     */
    /** Translates a blur radius in pixels to a ratio between 0 to 1. */
    fun ratioOfBlurRadius(blur: Float): Float {
        if (blur == 0f) {
            return 0f
        }
        return MathUtils.map(minBlurRadius, maxBlurRadius,
                0f /* maxStart */, 1f /* maxStop */, blur)
        return MathUtils.map(
            minBlurRadius,
            maxBlurRadius,
            0f /* maxStart */,
            1f /* maxStop */,
            blur,
        )
    }

    /**
@@ -91,16 +101,20 @@ open class BlurUtils @Inject constructor(
     * early-wakeup flag in SurfaceFlinger.
     */
    fun prepareBlur(viewRootImpl: ViewRootImpl?, radius: Int) {
        if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid ||
            !shouldBlur(radius) || earlyWakeupEnabled
        if (
            viewRootImpl == null ||
                !viewRootImpl.surfaceControl.isValid ||
                !shouldBlur(radius) ||
                earlyWakeupEnabled
        ) {
            return
        }
        updateTransactionApplier(viewRootImpl)
        val builder =
            SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(viewRootImpl.surfaceControl)
        if (lastAppliedBlur == 0 && radius != 0) {
            createTransaction().use {
                earlyWakeupStart(it, "eEarlyWakeup (prepareBlur)")
                it.apply()
            }
            earlyWakeupStart(builder, "eEarlyWakeup (prepareBlur)")
            transactionApplier.scheduleApply(builder.build())
        }
    }

@@ -115,11 +129,13 @@ open class BlurUtils @Inject constructor(
        if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid) {
            return
        }
        createTransaction().use {
        updateTransactionApplier(viewRootImpl)
        val builder =
            SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(viewRootImpl.surfaceControl)
        if (shouldBlur(radius)) {
                it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
            builder.withBackgroundBlur(radius)
            if (!earlyWakeupEnabled && lastAppliedBlur == 0 && radius != 0) {
                    earlyWakeupStart(it, "eEarlyWakeup (applyBlur)")
                earlyWakeupStart(builder, "eEarlyWakeup (applyBlur)")
            }
            if (
                earlyWakeupEnabled &&
@@ -127,13 +143,18 @@ open class BlurUtils @Inject constructor(
                    radius == 0 &&
                    !persistentEarlyWakeupRequired
            ) {
                    earlyWakeupEnd(it, "applyBlur")
                earlyWakeupEnd(builder, "applyBlur")
            }
            lastAppliedBlur = radius
        }
            it.setOpaque(viewRootImpl.surfaceControl, opaque)
            it.apply()
        builder.withOpaque(opaque)
        transactionApplier.scheduleApply(builder.build())
    }

    private fun updateTransactionApplier(viewRootImpl: ViewRootImpl) {
        if (lastTargetViewRootImpl == viewRootImpl) return
        _transactionApplier = SyncRtSurfaceTransactionApplier(viewRootImpl.view)
        lastTargetViewRootImpl = viewRootImpl
    }

    private fun v(verboseLog: String) {
@@ -141,26 +162,27 @@ open class BlurUtils @Inject constructor(
    }

    @SuppressLint("MissingPermission")
    private fun earlyWakeupStart(transaction: SurfaceControl.Transaction, traceMethodName: String) {
    private fun earlyWakeupStart(
        builder: SyncRtSurfaceTransactionApplier.SurfaceParams.Builder,
        traceMethodName: String,
    ) {
        v("earlyWakeupStart from $traceMethodName")
        Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, TRACK_NAME, traceMethodName, 0)
        transaction.setEarlyWakeupStart()
        builder.withEarlyWakeupStart()
        earlyWakeupEnabled = true
    }

    @SuppressLint("MissingPermission")
    private fun earlyWakeupEnd(transaction: SurfaceControl.Transaction, loggingContext: String) {
    private fun earlyWakeupEnd(
        builder: SyncRtSurfaceTransactionApplier.SurfaceParams.Builder,
        loggingContext: String,
    ) {
        v("earlyWakeupEnd from $loggingContext")
        transaction.setEarlyWakeupEnd()
        builder.withEarlyWakeupEnd()
        Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, TRACK_NAME, 0)
        earlyWakeupEnabled = false
    }

    @VisibleForTesting
    open fun createTransaction(): SurfaceControl.Transaction {
        return SurfaceControl.Transaction()
    }

    private fun shouldBlur(radius: Int): Boolean {
        return supportsBlursOnWindows() ||
            ((Flags.notificationShadeBlur() || Flags.bouncerUiRevamp()) &&
@@ -172,15 +194,16 @@ open class BlurUtils @Inject constructor(
    /**
     * If this device can render blurs.
     *
     * @see android.view.SurfaceControl.Transaction#setBackgroundBlurRadius(SurfaceControl, int)
     * @return {@code true} when supported.
     * @see android.view.SurfaceControl.Transaction#setBackgroundBlurRadius(SurfaceControl, int)
     */
    open fun supportsBlursOnWindows(): Boolean {
        return supportsBlursOnWindowsBase() && crossWindowBlurListeners.isCrossWindowBlurEnabled
    }

    private fun supportsBlursOnWindowsBase(): Boolean {
        return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx() &&
        return CROSS_WINDOW_BLUR_SUPPORTED &&
            ActivityManager.isHighEndGfx() &&
            !SystemProperties.getBoolean("persist.sysui.disableBlur", false)
    }

@@ -203,12 +226,14 @@ open class BlurUtils @Inject constructor(
    fun setPersistentEarlyWakeup(persistentWakeup: Boolean, viewRootImpl: ViewRootImpl?) {
        persistentEarlyWakeupRequired = persistentWakeup
        if (viewRootImpl == null || !supportsBlursOnWindows()) return

        updateTransactionApplier(viewRootImpl)
        val builder =
            SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(viewRootImpl.surfaceControl)
        if (persistentEarlyWakeupRequired) {
            if (earlyWakeupEnabled) return
            createTransaction().use {
                earlyWakeupStart(it, "setEarlyWakeup")
                it.apply()
            }
            earlyWakeupStart(builder, "setEarlyWakeup")
            transactionApplier.scheduleApply(builder.build())
        } else {
            if (!earlyWakeupEnabled) return
            if (lastAppliedBlur > 0) {
@@ -219,10 +244,8 @@ open class BlurUtils @Inject constructor(
                        " was still active",
                )
            }
            createTransaction().use {
                earlyWakeupEnd(it, "resetEarlyWakeup")
                it.apply()
            }
            earlyWakeupEnd(builder, "resetEarlyWakeup")
            transactionApplier.scheduleApply(builder.build())
        }
    }