From d31ffd3c576c52298348687bb8fc30a1c3a57dc6 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 21 Jan 2020 18:21:22 -0800 Subject: [PATCH] Fix BlurUtils crash We need to abort the operation if the given SurfaceControl is invalid. Test: atest BlurUtilsTest Fixes: 148110676 Change-Id: Iaed655e06d48f4d7dd6ee2df25838188e24813c6 --- .../android/systemui/statusbar/BlurUtils.kt | 15 +++- .../systemui/statusbar/BlurUtilsTest.kt | 82 +++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt index 083fbc92dc68a..ab69d477c2ee9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt @@ -22,6 +22,7 @@ import android.os.SystemProperties import android.util.MathUtils import android.view.SurfaceControl import android.view.ViewRootImpl +import androidx.annotation.VisibleForTesting import com.android.internal.util.IndentingPrintWriter import com.android.systemui.DumpController import com.android.systemui.Dumpable @@ -33,7 +34,7 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class BlurUtils @Inject constructor( +open class BlurUtils @Inject constructor( @Main private val resources: Resources, val dumpController: DumpController ) : Dumpable { @@ -63,22 +64,28 @@ class BlurUtils @Inject constructor( * @param radius blur radius in pixels. */ fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int) { - if (viewRootImpl == null || !supportsBlursOnWindows()) { + if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid || + !supportsBlursOnWindows()) { return } - SurfaceControl.Transaction().use { + createTransaction().use { it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius) it.apply() } } + @VisibleForTesting + open fun createTransaction(): SurfaceControl.Transaction { + return SurfaceControl.Transaction() + } + /** * If this device can render blurs. * * @see android.view.SurfaceControl.Transaction#setBackgroundBlurRadius(SurfaceControl, int) * @return {@code true} when supported. */ - fun supportsBlursOnWindows(): Boolean { + open fun supportsBlursOnWindows(): Boolean { return blurSysProp && ActivityManager.isHighEndGfx() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt new file mode 100644 index 0000000000000..c180a889a7ece --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar + +import android.content.res.Resources +import android.view.SurfaceControl +import android.view.ViewRootImpl +import androidx.test.filters.SmallTest +import com.android.systemui.DumpController +import com.android.systemui.SysuiTestCase +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.eq +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +@SmallTest +class BlurUtilsTest : SysuiTestCase() { + + @Mock lateinit var resources: Resources + @Mock lateinit var dumpController: DumpController + @Mock lateinit var transaction: SurfaceControl.Transaction + lateinit var blurUtils: BlurUtils + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + blurUtils = TestableBlurUtils() + } + + @Test + fun testApplyBlur_noViewRoot_doesntCrash() { + blurUtils.applyBlur(null /* viewRootImple */, 10 /* radius */) + } + + @Test + fun testApplyBlur_invalidSurfaceControl() { + val surfaceControl = mock(SurfaceControl::class.java) + val viewRootImpl = mock(ViewRootImpl::class.java) + `when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl) + blurUtils.applyBlur(viewRootImpl, 10 /* radius */) + } + + @Test + fun testApplyBlur_success() { + val radius = 10 + val surfaceControl = mock(SurfaceControl::class.java) + val viewRootImpl = mock(ViewRootImpl::class.java) + `when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl) + `when`(surfaceControl.isValid).thenReturn(true) + blurUtils.applyBlur(viewRootImpl, radius) + verify(transaction).setBackgroundBlurRadius(eq(surfaceControl), eq(radius)) + verify(transaction).apply() + } + + inner class TestableBlurUtils() : BlurUtils(resources, dumpController) { + override fun supportsBlursOnWindows(): Boolean { + return true + } + + override fun createTransaction(): SurfaceControl.Transaction { + return transaction + } + } +} \ No newline at end of file