1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar 18 19 import android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED 20 21 import android.app.ActivityManager 22 import android.content.res.Resources 23 import android.os.SystemProperties 24 import android.util.IndentingPrintWriter 25 import android.util.MathUtils 26 import android.view.CrossWindowBlurListeners 27 import android.view.SurfaceControl 28 import android.view.ViewRootImpl 29 import androidx.annotation.VisibleForTesting 30 import com.android.systemui.Dumpable 31 import com.android.systemui.R 32 import com.android.systemui.dagger.SysUISingleton 33 import com.android.systemui.dagger.qualifiers.Main 34 import com.android.systemui.dump.DumpManager 35 import java.io.FileDescriptor 36 import java.io.PrintWriter 37 import javax.inject.Inject 38 39 @SysUISingleton 40 open class BlurUtils @Inject constructor( 41 @Main private val resources: Resources, 42 private val crossWindowBlurListeners: CrossWindowBlurListeners, 43 dumpManager: DumpManager 44 ) : Dumpable { 45 val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius) 46 val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius) 47 48 private var lastAppliedBlur = 0 49 50 init { 51 dumpManager.registerDumpable(javaClass.name, this) 52 } 53 54 /** 55 * Translates a ratio from 0 to 1 to a blur radius in pixels. 56 */ 57 fun blurRadiusOfRatio(ratio: Float): Float { 58 if (ratio == 0f) { 59 return 0f 60 } 61 return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio) 62 } 63 64 /** 65 * Translates a blur radius in pixels to a ratio between 0 to 1. 66 */ 67 fun ratioOfBlurRadius(blur: Float): Float { 68 if (blur == 0f) { 69 return 0f 70 } 71 return MathUtils.map(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), 72 0f /* maxStart */, 1f /* maxStop */, blur) 73 } 74 75 /** 76 * Applies background blurs to a {@link ViewRootImpl}. 77 * 78 * @param viewRootImpl The window root. 79 * @param radius blur radius in pixels. 80 * @param opaque if surface is opaque, regardless or having blurs or no. 81 */ 82 fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int, opaque: Boolean) { 83 if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid) { 84 return 85 } 86 createTransaction().use { 87 if (supportsBlursOnWindows()) { 88 it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius) 89 if (lastAppliedBlur == 0 && radius != 0) { 90 it.setEarlyWakeupStart() 91 } 92 if (lastAppliedBlur != 0 && radius == 0) { 93 it.setEarlyWakeupEnd() 94 } 95 lastAppliedBlur = radius 96 } 97 it.setOpaque(viewRootImpl.surfaceControl, opaque) 98 it.apply() 99 } 100 } 101 102 @VisibleForTesting 103 open fun createTransaction(): SurfaceControl.Transaction { 104 return SurfaceControl.Transaction() 105 } 106 107 /** 108 * If this device can render blurs. 109 * 110 * @see android.view.SurfaceControl.Transaction#setBackgroundBlurRadius(SurfaceControl, int) 111 * @return {@code true} when supported. 112 */ 113 open fun supportsBlursOnWindows(): Boolean { 114 return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx() && 115 crossWindowBlurListeners.isCrossWindowBlurEnabled() && 116 !SystemProperties.getBoolean("persist.sysui.disableBlur", false) 117 } 118 119 override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { 120 IndentingPrintWriter(pw, " ").let { 121 it.println("BlurUtils:") 122 it.increaseIndent() 123 it.println("minBlurRadius: $minBlurRadius") 124 it.println("maxBlurRadius: $maxBlurRadius") 125 it.println("supportsBlursOnWindows: ${supportsBlursOnWindows()}") 126 it.println("CROSS_WINDOW_BLUR_SUPPORTED: $CROSS_WINDOW_BLUR_SUPPORTED") 127 it.println("isHighEndGfx: ${ActivityManager.isHighEndGfx()}") 128 } 129 } 130 } 131