blob: cfbe3b29783aeb5e5d401f00ee622fe63860df0f [file] [log] [blame]
/*
* 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.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED
import android.app.ActivityManager
import android.content.res.Resources
import android.os.SystemProperties
import android.util.IndentingPrintWriter
import android.util.MathUtils
import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject
@SysUISingleton
open class BlurUtils @Inject constructor(
@Main private val resources: Resources,
private val crossWindowBlurListeners: CrossWindowBlurListeners,
dumpManager: DumpManager
) : Dumpable {
val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius)
private var lastAppliedBlur = 0
init {
dumpManager.registerDumpable(javaClass.name, this)
}
/**
* Translates a ratio from 0 to 1 to a blur radius in pixels.
*/
fun blurRadiusOfRatio(ratio: Float): Float {
if (ratio == 0f) {
return 0f
}
return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio)
}
/**
* 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.toFloat(), maxBlurRadius.toFloat(),
0f /* maxStart */, 1f /* maxStop */, blur)
}
/**
* Applies background blurs to a {@link ViewRootImpl}.
*
* @param viewRootImpl The window root.
* @param radius blur radius in pixels.
* @param opaque if surface is opaque, regardless or having blurs or no.
*/
fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int, opaque: Boolean) {
if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid ||
!supportsBlursOnWindows()) {
return
}
createTransaction().use {
it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
it.setOpaque(viewRootImpl.surfaceControl, opaque)
if (lastAppliedBlur == 0 && radius != 0) {
it.setEarlyWakeupStart()
}
if (lastAppliedBlur != 0 && radius == 0) {
it.setEarlyWakeupEnd()
}
it.apply()
}
lastAppliedBlur = radius
}
@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.
*/
open fun supportsBlursOnWindows(): Boolean {
return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx() &&
crossWindowBlurListeners.isCrossWindowBlurEnabled() &&
!SystemProperties.getBoolean("persist.sysui.disableBlur", false)
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
IndentingPrintWriter(pw, " ").let {
it.println("BlurUtils:")
it.increaseIndent()
it.println("minBlurRadius: $minBlurRadius")
it.println("maxBlurRadius: $maxBlurRadius")
it.println("supportsBlursOnWindows: ${supportsBlursOnWindows()}")
it.println("CROSS_WINDOW_BLUR_SUPPORTED: $CROSS_WINDOW_BLUR_SUPPORTED")
it.println("isHighEndGfx: ${ActivityManager.isHighEndGfx()}")
}
}
}