Loading core/java/android/view/SyncRtSurfaceTransactionApplier.java +50 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.SuppressLint; import android.graphics.Matrix; import android.graphics.Rect; import android.view.SurfaceControl.Transaction; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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); } } /** Loading Loading @@ -172,6 +186,7 @@ public class SyncRtSurfaceTransactionApplier { Rect windowCrop; int layer; boolean visible; boolean opaque; Transaction mergeTransaction; /** Loading Loading @@ -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; Loading @@ -284,6 +330,7 @@ public class SyncRtSurfaceTransactionApplier { this.backgroundBlurRadius = backgroundBlurRadius; this.visible = visible; this.mergeTransaction = mergeTransaction; this.opaque = opaque; } private final int flags; Loading Loading @@ -312,5 +359,6 @@ public class SyncRtSurfaceTransactionApplier { public final boolean visible; public final Transaction mergeTransaction; public final boolean opaque; } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt +31 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() { Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 } } } packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +88 −65 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 */ Loading @@ -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 Loading @@ -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, ) } /** Loading @@ -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()) } } Loading @@ -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 && Loading @@ -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) { Loading @@ -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()) && Loading @@ -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) } Loading @@ -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) { Loading @@ -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()) } } Loading Loading
core/java/android/view/SyncRtSurfaceTransactionApplier.java +50 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.SuppressLint; import android.graphics.Matrix; import android.graphics.Rect; import android.view.SurfaceControl.Transaction; Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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); } } /** Loading Loading @@ -172,6 +186,7 @@ public class SyncRtSurfaceTransactionApplier { Rect windowCrop; int layer; boolean visible; boolean opaque; Transaction mergeTransaction; /** Loading Loading @@ -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; Loading @@ -284,6 +330,7 @@ public class SyncRtSurfaceTransactionApplier { this.backgroundBlurRadius = backgroundBlurRadius; this.visible = visible; this.mergeTransaction = mergeTransaction; this.opaque = opaque; } private final int flags; Loading Loading @@ -312,5 +359,6 @@ public class SyncRtSurfaceTransactionApplier { public final boolean visible; public final Transaction mergeTransaction; public final boolean opaque; } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/BlurUtilsTest.kt +31 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() { Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 } } }
packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +88 −65 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 */ Loading @@ -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 Loading @@ -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, ) } /** Loading @@ -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()) } } Loading @@ -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 && Loading @@ -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) { Loading @@ -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()) && Loading @@ -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) } Loading @@ -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) { Loading @@ -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()) } } Loading