summaryrefslogtreecommitdiff
path: root/graphics/java/android
diff options
context:
space:
mode:
authorBrian Orr <brianorr@google.com>2021-06-15 12:47:53 -0700
committerDaniel Norman <danielnorman@google.com>2021-06-17 13:37:54 -0700
commit71c831703ae59baf47e0afe611fecd714c481cdf (patch)
tree06731a987032723085b9e1a65951cf96abbc19cf /graphics/java/android
parent065c9e9a6e9d61d4383a91721eb56a3de253bdbe (diff)
parent81833820d54b9a6b27894f9f8dfd72222d416992 (diff)
Merge SP1A.210604.001
Change-Id: I5200ee05285ae422d5e9c1c00f45709a5d6188be
Diffstat (limited to 'graphics/java/android')
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java3
-rw-r--r--graphics/java/android/graphics/RadialGradient.java20
-rw-r--r--graphics/java/android/graphics/drawable/RippleAnimationSession.java11
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java10
-rw-r--r--graphics/java/android/graphics/drawable/RippleShader.java61
-rw-r--r--graphics/java/android/graphics/fonts/Font.java17
-rw-r--r--graphics/java/android/graphics/fonts/FontCustomizationParser.java6
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java68
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);
}
}