From e20226355a3e0678b7e2d4414a961ced31384dc2 Mon Sep 17 00:00:00 2001 From: Shan Huang Date: Thu, 2 Dec 2021 03:19:30 +0000 Subject: [PATCH] Add dwell ripple shader Bug:206986888 Test: patch ag/16375647 and "adb shell cmd statusbar auth-ripple dwell" Change-Id: I99e18d1d8415204d291bbfd3782bef7bed0e99b4 --- .../statusbar/charging/DwellRippleShader.kt | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt new file mode 100644 index 0000000000000..a1d086b5d768c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 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.charging + +import android.graphics.Color +import android.graphics.PointF +import android.graphics.RuntimeShader +import android.util.MathUtils + +/** + * Shader class that renders a distorted ripple for the UDFPS dwell effect. + * Adjustable shader parameters: + * - progress + * - origin + * - color + * - time + * - maxRadius + * - distortionStrength. + * See per field documentation for more details. + * + * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java. + */ +class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) { + companion object { + private const val SHADER_UNIFORMS = """uniform vec2 in_origin; + uniform float in_time; + uniform float in_radius; + uniform float in_blur; + uniform vec4 in_color; + uniform float in_phase1; + uniform float in_phase2; + uniform float in_distortion_strength;""" + private const val SHADER_LIB = """ + float softCircle(vec2 uv, vec2 xy, float radius, float blur) { + float blurHalf = blur * 0.5; + float d = distance(uv, xy); + return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius); + } + + float softRing(vec2 uv, vec2 xy, float radius, float blur) { + float thickness_half = radius * 0.25; + float circle_outer = softCircle(uv, xy, radius + thickness_half, blur); + float circle_inner = softCircle(uv, xy, radius - thickness_half, blur); + return circle_outer - circle_inner; + } + + vec2 distort(vec2 p, float time, float distort_amount_xy, float frequency) { + return p + vec2(sin(p.x * frequency + in_phase1), + cos(p.y * frequency * 1.23 + in_phase2)) * distort_amount_xy; + } + + vec4 ripple(vec2 p, float distort_xy, float frequency) { + vec2 p_distorted = distort(p, in_time, distort_xy, frequency); + float circle = softCircle(p_distorted, in_origin, in_radius * 1.2, in_blur); + float rippleAlpha = max(circle, + softRing(p_distorted, in_origin, in_radius, in_blur)) * 0.25; + return in_color * rippleAlpha; + } + """ + private const val SHADER_MAIN = """vec4 main(vec2 p) { + vec4 color1 = ripple(p, + 12 * in_distortion_strength, // distort_xy + 0.012 // frequency + ); + vec4 color2 = ripple(p, + 17.5 * in_distortion_strength, // distort_xy + 0.018 // frequency + ); + // Alpha blend between two layers. + return vec4(color1.xyz + color2.xyz + * (1 - color1.w), color1.w + color2.w * (1-color1.w)); + }""" + private const val SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN + } + + /** + * Maximum radius of the ripple. + */ + var maxRadius: Float = 0.0f + + /** + * Origin coordinate of the ripple. + */ + var origin: PointF = PointF() + set(value) { + field = value + setUniform("in_origin", floatArrayOf(value.x, value.y)) + } + + /** + * Progress of the ripple. Float value between [0, 1]. + */ + var progress: Float = 0.0f + set(value) { + field = value + setUniform("in_radius", + (1 - (1 - value) * (1 - value) * (1 - value))* maxRadius) + setUniform("in_blur", MathUtils.lerp(1f, 0.7f, value)) + } + + /** + * Distortion strength between [0, 1], with 0 being no distortion and 1 being full distortion. + */ + var distortionStrength: Float = 0.0f + set(value) { + field = value + setUniform("in_distortion_strength", value) + } + + /** + * Play time since the start of the effect in seconds. + */ + var time: Float = 0.0f + set(value) { + field = value * 0.001f + setUniform("in_time", field) + setUniform("in_phase1", field * 2f + 0.367f) + setUniform("in_phase2", field * 5.2f * 1.531f) + } + + /** + * A hex value representing the ripple color, in the format of ARGB + */ + var color: Int = 0xffffff.toInt() + set(value) { + field = value + val color = Color.valueOf(value) + setUniform("in_color", floatArrayOf(color.red(), + color.green(), color.blue(), color.alpha())) + } +}