diff options
Diffstat (limited to 'graphics/java')
8 files changed, 128 insertions, 68 deletions
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index 8f1223b5eeaf..954d062b55e9 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -1195,6 +1195,7 @@ public class HardwareRenderer { // so not checking for isolated process here. initHintSession(); + nSetIsHighEndGfx(ActivityManager.isHighEndGfx()); // Defensively clear out the context in case we were passed a context that can leak // if we live longer than it, e.g. an activity context. mContext = null; @@ -1315,6 +1316,8 @@ public class HardwareRenderer { private static native void nSetSdrWhitePoint(long nativeProxy, float whitePoint); + private static native void nSetIsHighEndGfx(boolean isHighEndGfx); + private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); private static native void nDestroy(long nativeProxy, long rootRenderNode); diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index 199365e9a1e2..e582e66e1627 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -122,14 +122,18 @@ public class RadialGradient extends Shader { * between the center and edge of the circle. * @param tileMode The Shader tiling mode * - * @throws IllegalArgumentException If one of the following circumstances: - * - There are less than two colors - * - The colors do not share the same {@link ColorSpace} - * - The colors do not use a valid {@link ColorSpace} - * - The {@code stops} parameter is not {@code null} and has a different length - * from {@code colors}. - * - The {@param startRadius} is negative - * - The {@param endRadius} is less than or equal to zero + * @throws IllegalArgumentException In one of the following circumstances: + * <ul> + * <li>There are less than two colors</li> + * <li>The colors do not share the same {@link ColorSpace}</li> + * <li>The colors do not use a valid {@link ColorSpace}</li> + * <li> + * The {@code stops} parameter is not {@code null} and has a different length from + * {@code colors}. + * </li> + * <li>The {@code startRadius} is negative</li> + * <li>The {@code endRadius} is less than or equal to zero</li> + * </ul> */ public RadialGradient(float startX, float startY, @FloatRange(from = 0.0f) float startRadius, float endX, float endY, @FloatRange(from = 0.0f, fromInclusive = false) float endRadius, diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java index ee867ddd5915..55fb83c81961 100644 --- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java +++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java @@ -40,9 +40,9 @@ import java.util.function.Consumer; public final class RippleAnimationSession { private static final String TAG = "RippleAnimationSession"; private static final int ENTER_ANIM_DURATION = 450; - private static final int EXIT_ANIM_DURATION = 225; + private static final int EXIT_ANIM_DURATION = 375; private static final long NOISE_ANIMATION_DURATION = 7000; - private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120; + private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 214; private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); @@ -61,12 +61,12 @@ public final class RippleAnimationSession { } @NonNull RippleAnimationSession enter(Canvas canvas) { + mStartTime = AnimationUtils.currentAnimationTimeMillis(); if (isHwAccelerated(canvas)) { enterHardware((RecordingCanvas) canvas); } else { enterSoftware(); } - mStartTime = AnimationUtils.currentAnimationTimeMillis(); return this; } @@ -160,7 +160,8 @@ public final class RippleAnimationSession { RenderNodeAnimator expand = new RenderNodeAnimator(props.getProgress(), .5f); expand.setTarget(canvas); - RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE); + RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), + mStartTime + MAX_NOISE_PHASE); loop.setTarget(canvas); startAnimation(expand, loop); } @@ -190,7 +191,7 @@ public final class RippleAnimationSession { notifyUpdate(); mProperties.getShader().setProgress((float) expand.getAnimatedValue()); }); - ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE); + ValueAnimator loop = ValueAnimator.ofFloat(mStartTime, mStartTime + MAX_NOISE_PHASE); loop.addUpdateListener(updatedAnimation -> { notifyUpdate(); mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue()); diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 518fceb60049..73e65c2ec050 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -50,6 +50,7 @@ import android.graphics.Rect; import android.graphics.Shader; import android.os.Build; import android.util.AttributeSet; +import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; import com.android.internal.R; @@ -151,7 +152,7 @@ public class RippleDrawable extends LayerDrawable { /** The maximum number of ripples supported. */ private static final int MAX_RIPPLES = 10; private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final int DEFAULT_EFFECT_COLOR = 0x80ffffff; + private static final int DEFAULT_EFFECT_COLOR = 0x8dffffff; /** Temporary flag for teamfood. **/ private static final boolean FORCE_PATTERNED_STYLE = true; @@ -970,15 +971,16 @@ public class RippleDrawable extends LayerDrawable { ? mState.mColor.getColorForState(getState(), Color.BLACK) : mMaskColorFilter.getColor()); final int effectColor = mState.mEffectColor.getColorForState(getState(), Color.MAGENTA); + final float noisePhase = AnimationUtils.currentAnimationTimeMillis(); shader.setColor(color, effectColor); shader.setOrigin(cx, cy); shader.setTouch(x, y); - shader.setResolution(w, h, mState.mDensity); - shader.setNoisePhase(0); + shader.setResolution(w, h); + shader.setNoisePhase(noisePhase); shader.setRadius(radius); shader.setProgress(.0f); properties = new RippleAnimationSession.AnimationProperties<>( - cx, cy, radius, 0f, p, 0f, color, shader); + cx, cy, radius, noisePhase, p, 0f, color, shader); if (mMaskShader == null) { shader.setShader(null); } else { diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java index 6c0981afa2c9..57b322334867 100644 --- a/graphics/java/android/graphics/drawable/RippleShader.java +++ b/graphics/java/android/graphics/drawable/RippleShader.java @@ -20,7 +20,6 @@ import android.annotation.ColorInt; import android.graphics.Color; import android.graphics.RuntimeShader; import android.graphics.Shader; -import android.util.DisplayMetrics; final class RippleShader extends RuntimeShader { private static final String SHADER_UNIFORMS = "uniform vec2 in_origin;\n" @@ -50,15 +49,17 @@ final class RippleShader extends RuntimeShader { + "}" + "const float PI = 3.1415926535897932384626;\n" + "\n" + + "float threshold(float v, float l, float h) {\n" + + " return step(l, v) * (1.0 - step(h, v));\n" + + "}\n" + "float sparkles(vec2 uv, float t) {\n" + " float n = triangleNoise(uv);\n" + " float s = 0.0;\n" + " for (float i = 0; i < 4; i += 1) {\n" - + " float l = i * 0.01;\n" - + " float h = l + 0.2;\n" - + " float o = smoothstep(n - l, h, n);\n" - + " o *= abs(sin(PI * o * (t + 0.55 * i)));\n" - + " s += o;\n" + + " float l = i * 0.1;\n" + + " float h = l + 0.05;\n" + + " float o = sin(PI * (t + 0.35 * i));\n" + + " s += threshold(n + o, l, h);\n" + " }\n" + " return saturate(s) * in_sparkleColor.a;\n" + "}\n" @@ -68,7 +69,7 @@ final class RippleShader extends RuntimeShader { + " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n" + "}\n" + "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n" - + " float thickness = 0.3 * radius;\n" + + " float thickness = 0.05 * radius;\n" + " float currentRadius = radius * progress;\n" + " float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n" + " float circle_inner = softCircle(uv, xy, max(currentRadius - thickness, 0.), " @@ -91,7 +92,7 @@ final class RippleShader extends RuntimeShader { + " return softCircle(coord, vec2(normal_radius), radius, radius * 50.0);\n" + "}\n" + "float turbulence(vec2 uv, float t) {\n" - + " const vec2 scale = vec2(1.5);\n" + + " const vec2 scale = vec2(0.8);\n" + " uv = uv * scale;\n" + " float g1 = circle_grid(scale, uv, t, in_tCircle1, in_tRotation1, 0.17);\n" + " float g2 = circle_grid(scale, uv, t, in_tCircle2, in_tRotation2, 0.2);\n" @@ -100,12 +101,12 @@ final class RippleShader extends RuntimeShader { + " return saturate(0.45 + 0.8 * v);\n" + "}\n"; private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n" - + " float fadeIn = subProgress(0., 0.1, in_progress);\n" - + " float scaleIn = subProgress(0., 0.45, in_progress);\n" - + " float fadeOutNoise = subProgress(0.5, 0.95, in_progress);\n" - + " float fadeOutRipple = subProgress(0.5, 1., in_progress);\n" - + " vec2 center = mix(in_touch, in_origin, scaleIn);\n" - + " float ring = softRing(p, center, in_maxRadius, scaleIn, 0.45);\n" + + " float fadeIn = subProgress(0., 0.13, in_progress);\n" + + " float scaleIn = subProgress(0., 1.0, in_progress);\n" + + " float fadeOutNoise = subProgress(0.4, 0.5, in_progress);\n" + + " float fadeOutRipple = subProgress(0.4, 1., in_progress);\n" + + " vec2 center = mix(in_touch, in_origin, saturate(in_progress * 2.0));\n" + + " float ring = softRing(p, center, in_maxRadius, scaleIn, 1.);\n" + " float alpha = min(fadeIn, 1. - fadeOutNoise);\n" + " vec2 uv = p * in_resolutionScale;\n" + " vec2 densityUv = uv - mod(uv, in_noiseScale);\n" @@ -113,7 +114,7 @@ final class RippleShader extends RuntimeShader { + " float sparkleAlpha = sparkles(densityUv, in_noisePhase) * ring * alpha " + "* turbulence;\n" + " float fade = min(fadeIn, 1. - fadeOutRipple);\n" - + " float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 0.2) * fade " + + " float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 1.) * fade " + "* in_color.a;\n" + " vec4 waveColor = vec4(in_color.rgb * waveAlpha, waveAlpha);\n" + " vec4 sparkleColor = vec4(in_sparkleColor.rgb * in_sparkleColor.a, " @@ -125,9 +126,6 @@ final class RippleShader extends RuntimeShader { private static final double PI_ROTATE_RIGHT = Math.PI * 0.0078125; private static final double PI_ROTATE_LEFT = Math.PI * -0.0078125; - private float mNoisePhase; - private float mProgress; - RippleShader() { super(SHADER, false); } @@ -140,16 +138,7 @@ final class RippleShader extends RuntimeShader { } public void setRadius(float radius) { - setUniform("in_maxRadius", radius); - } - - /** - * Continuous offset used as noise phase. - */ - public void setNoisePhase(float phase) { - mNoisePhase = phase; - setUniform("in_noisePhase", phase); - updateTurbulence(); + setUniform("in_maxRadius", radius * 2.3f); } public void setOrigin(float x, float y) { @@ -161,18 +150,20 @@ final class RippleShader extends RuntimeShader { } public void setProgress(float progress) { - mProgress = progress; setUniform("in_progress", progress); - updateTurbulence(); } - private void updateTurbulence() { - final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI); - setUniform("in_turbulencePhase", turbulencePhase); + /** + * Continuous offset used as noise phase. + */ + public void setNoisePhase(float phase) { + setUniform("in_noisePhase", phase * 0.001f); // // Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h // + final float turbulencePhase = phase; + setUniform("in_turbulencePhase", turbulencePhase); final float scale = 1.5f; setUniform("in_tCircle1", new float[]{ (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))), @@ -212,8 +203,8 @@ final class RippleShader extends RuntimeShader { sparkleColor.green(), sparkleColor.blue(), sparkleColor.alpha()}); } - public void setResolution(float w, float h, int density) { - final float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE; + public void setResolution(float w, float h) { + final float densityScale = 2.1f; setUniform("in_resolutionScale", new float[] {1f / w, 1f / h}); setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h}); } diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index f826b24b2df2..69cd8bdb3e70 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -801,6 +801,15 @@ public final class Font { return myBuffer.equals(otherBuffer); } + /** @hide */ + public boolean paramEquals(@NonNull Font f) { + return f.getStyle().equals(getStyle()) + && f.getTtcIndex() == getTtcIndex() + && Arrays.equals(f.getAxes(), getAxes()) + && Objects.equals(f.getLocaleList(), getLocaleList()) + && Objects.equals(getFile(), f.getFile()); + } + @Override public boolean equals(@Nullable Object o) { if (o == this) { @@ -818,13 +827,7 @@ public final class Font { return true; } - boolean paramEqual = f.getStyle().equals(getStyle()) - && f.getTtcIndex() == getTtcIndex() - && Arrays.equals(f.getAxes(), getAxes()) - && Objects.equals(f.getLocaleList(), getLocaleList()) - && Objects.equals(getFile(), f.getFile()); - - if (!paramEqual) { + if (!paramEquals(f)) { return false; } diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java index 9c01a4be381f..df47f73eb04a 100644 --- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java +++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java @@ -134,7 +134,11 @@ public class FontCustomizationParser { throw new IllegalArgumentException("customizationType must be specified"); } if (customizationType.equals("new-named-family")) { - out.add(FontListParser.readFamily(parser, fontDir, updatableFontMap, false)); + FontFamily fontFamily = FontListParser.readFamily( + parser, fontDir, updatableFontMap, false); + if (fontFamily != null) { + out.add(fontFamily); + } } else { throw new IllegalArgumentException("Unknown customizationType=" + customizationType); } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 255f9e659c36..8d69d447f4e0 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -46,7 +47,6 @@ import java.util.Set; */ public final class SystemFonts { private static final String TAG = "SystemFonts"; - private static final String DEFAULT_FAMILY = "sans-serif"; private static final String FONTS_XML = "/system/etc/fonts.xml"; /** @hide */ @@ -59,7 +59,36 @@ public final class SystemFonts { private static final Object LOCK = new Object(); private static @GuardedBy("sLock") Set<Font> sAvailableFonts; - private static @GuardedBy("sLock") Map<String, FontFamily[]> sFamilyMap; + + /** + * Helper wrapper class for skipping buffer equality check of Font#equals. + * + * Due to historical reasons, the Font#equals checks the byte-by-byte buffer equality which + * requires heavy IO work in getAvailableFonts. Since the fonts came from system are all regular + * file backed font instance and stored in the unique place, just comparing file path should be + * good enough for this case. + */ + private static final class SystemFontHashWrapper { + private final Font mFont; + SystemFontHashWrapper(Font font) { + mFont = font; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + // All system fonts are regular-file backed font instance, so no need to + // compare buffers. + return mFont.paramEquals(((SystemFontHashWrapper) o).mFont); + } + + @Override + public int hashCode() { + return Objects.hash(mFont); + } + } /** * Returns all available font files in the system. @@ -69,22 +98,39 @@ public final class SystemFonts { public static @NonNull Set<Font> getAvailableFonts() { synchronized (LOCK) { if (sAvailableFonts == null) { - Set<Font> set = new ArraySet<>(); + Set<SystemFontHashWrapper> set = new ArraySet<>(); for (Typeface tf : Typeface.getSystemFontMap().values()) { List<FontFamily> families = tf.getFallback(); for (int i = 0; i < families.size(); ++i) { FontFamily family = families.get(i); for (int j = 0; j < family.getSize(); ++j) { - set.add(family.getFont(j)); + set.add(new SystemFontHashWrapper(family.getFont(j))); } } } - sAvailableFonts = Collections.unmodifiableSet(set); + + // Unwrapping font instance for Set<Font> interface. The ArraySet#add won't call + // Font#equals function if none of two objects has the same hash, so following + // unwrapping won't cause bad performance due to byte-by-byte equality check. + ArraySet<Font> result = new ArraySet(set.size()); + for (SystemFontHashWrapper wrapper : set) { + result.add(wrapper.mFont); + } + sAvailableFonts = Collections.unmodifiableSet(result); } return sAvailableFonts; } } + /** + * @hide + */ + public static void resetAvailableFonts() { + synchronized (LOCK) { + sAvailableFonts = null; + } + } + private static @Nullable ByteBuffer mmap(@NonNull String fullPath) { try (FileInputStream file = new FileInputStream(fullPath)) { final FileChannel fileChannel = file.getChannel(); @@ -262,8 +308,14 @@ public final class SystemFonts { */ @VisibleForTesting public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) { + return buildSystemFallback(fontConfig, new ArrayMap<>()); + } + + /** @hide */ + @VisibleForTesting + public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig, + ArrayMap<String, ByteBuffer> outBufferCache) { final Map<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - final ArrayMap<String, ByteBuffer> bufferCache = new ArrayMap<>(); final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies(); final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>(); @@ -273,7 +325,7 @@ public final class SystemFonts { if (familyName == null) { continue; } - appendNamedFamily(xmlFamily, bufferCache, fallbackListMap); + appendNamedFamily(xmlFamily, outBufferCache, fallbackListMap); } // Then, add fallback fonts to the each fallback map. @@ -282,7 +334,7 @@ public final class SystemFonts { // The first family (usually the sans-serif family) is always placed immediately // after the primary family in the fallback. if (i == 0 || xmlFamily.getName() == null) { - pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache); + pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache); } } |