summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Roard <nicolasroard@google.com> 2025-04-04 02:14:38 +0000
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-04-09 18:26:24 -0700
commit03c576b78ba829e98efcc3aa32903e42fcabf251 (patch)
treee8f5a908364277300d0146557fbfde73519adfee
parente1e81661633dabd10c37237d48b20a9169771aac (diff)
Update to ToT RemoteCompose
Bug: 403275243 Flag: EXEMPT External Libraries Test: in GoB (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2b93290d447f79f0bcd2892b452265ed9e98e8b4) Merged-In: I3d42535338c3fe07874807b599c9df32620c2999 Change-Id: I3d42535338c3fe07874807b599c9df32620c2999
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java67
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/Operations.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/PaintContext.java27
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java74
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ColorAttribute.java214
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/ComponentData.java19
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java13
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Header.java18
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java3
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java2
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java86
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java35
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java24
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java15
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java534
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RunActionOperation.java145
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java149
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java9
22 files changed, 1047 insertions, 410 deletions
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 4e2c0b98295a..ab18f4209377 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.remotecompose.core.operations.BitmapData;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
+import com.android.internal.widget.remotecompose.core.operations.DataListFloat;
import com.android.internal.widget.remotecompose.core.operations.DrawContent;
import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
@@ -31,7 +32,6 @@ import com.android.internal.widget.remotecompose.core.operations.RootContentBeha
import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.TextData;
import com.android.internal.widget.remotecompose.core.operations.Theme;
-import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.layout.CanvasOperations;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.layout.Container;
@@ -69,7 +69,7 @@ public class CoreDocument implements Serializable {
public static final int PATCH_VERSION = 0;
// Internal version level
- public static final int DOCUMENT_API_LEVEL = 5;
+ public static final int DOCUMENT_API_LEVEL = 6;
// We also keep a more fine-grained BUILD number, exposed as
// ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD
@@ -113,6 +113,7 @@ public class CoreDocument implements Serializable {
private IntMap<Object> mDocProperties;
boolean mFirstPaint = true;
+ private boolean mIsUpdateDoc = false;
/** Returns a version number that is monotonically increasing. */
public static int getDocumentApiLevel() {
@@ -460,7 +461,8 @@ public class CoreDocument implements Serializable {
HashMap<Integer, FloatConstant> fltData = new HashMap<Integer, FloatConstant>();
HashMap<Integer, IntegerConstant> intData = new HashMap<Integer, IntegerConstant>();
HashMap<Integer, LongConstant> longData = new HashMap<Integer, LongConstant>();
- recursiveTreverse(
+ HashMap<Integer, DataListFloat> floatListData = new HashMap<Integer, DataListFloat>();
+ recursiveTraverse(
mOperations,
(op) -> {
if (op instanceof TextData) {
@@ -478,10 +480,13 @@ public class CoreDocument implements Serializable {
} else if (op instanceof LongConstant) {
LongConstant d = (LongConstant) op;
longData.put(d.mId, d);
+ } else if (op instanceof DataListFloat) {
+ DataListFloat d = (DataListFloat) op;
+ floatListData.put(d.mId, d);
}
});
- recursiveTreverse(
+ recursiveTraverse(
delta.mOperations,
(op) -> {
if (op instanceof TextData) {
@@ -489,7 +494,6 @@ public class CoreDocument implements Serializable {
TextData txtInDoc = txtData.get(t.mTextId);
if (txtInDoc != null) {
txtInDoc.update(t);
- Utils.log("update" + t.mText);
txtInDoc.markDirty();
}
} else if (op instanceof BitmapData) {
@@ -520,6 +524,13 @@ public class CoreDocument implements Serializable {
longInDoc.update(lc);
longInDoc.markDirty();
}
+ } else if (op instanceof DataListFloat) {
+ DataListFloat lc = (DataListFloat) op;
+ DataListFloat longInDoc = floatListData.get(lc.mId);
+ if (longInDoc != null) {
+ longInDoc.update(lc);
+ longInDoc.markDirty();
+ }
}
});
}
@@ -528,10 +539,10 @@ public class CoreDocument implements Serializable {
void visit(Operation op);
}
- private void recursiveTreverse(ArrayList<Operation> mOperations, Visitor visitor) {
+ private void recursiveTraverse(ArrayList<Operation> mOperations, Visitor visitor) {
for (Operation op : mOperations) {
if (op instanceof Container) {
- recursiveTreverse(((Component) op).mList, visitor);
+ recursiveTraverse(((Container) op).getList(), visitor);
}
visitor.visit(op);
}
@@ -1216,29 +1227,23 @@ public class CoreDocument implements Serializable {
* @return array of named variables or null
*/
public String[] getNamedVariables(int type) {
- int count = 0;
- for (Operation op : mOperations) {
+ ArrayList<String> ret = new ArrayList<>();
+ getNamedVars(type, mOperations, ret);
+ return ret.toArray(new String[0]);
+ }
+
+ private void getNamedVars(int type, ArrayList<Operation> ops, ArrayList<String> list) {
+ for (Operation op : ops) {
if (op instanceof NamedVariable) {
NamedVariable n = (NamedVariable) op;
if (n.mVarType == type) {
- count++;
+ list.add(n.mVarName);
}
}
- }
- if (count == 0) {
- return null;
- }
- String[] ret = new String[count];
- int i = 0;
- for (Operation op : mOperations) {
- if (op instanceof NamedVariable) {
- NamedVariable n = (NamedVariable) op;
- if (n.mVarType == type) {
- ret[i++] = n.mVarName;
- }
+ if (op instanceof Container) {
+ getNamedVars(type, ((Container) op).getList(), list);
}
}
- return ret;
}
//////////////////////////////////////////////////////////////////////////
@@ -1577,4 +1582,20 @@ public class CoreDocument implements Serializable {
}
}
}
+
+ /**
+ * Set if this is an update doc
+ *
+ * @param isUpdateDoc
+ */
+ public void setUpdateDoc(boolean isUpdateDoc) {
+ mIsUpdateDoc = isUpdateDoc;
+ }
+
+ /**
+ * @return if this is an update doc
+ */
+ public boolean isUpdateDoc() {
+ return mIsUpdateDoc;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 20252366e264..14d0a7560804 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -22,6 +22,7 @@ import com.android.internal.widget.remotecompose.core.operations.BitmapFontData;
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorAttribute;
import com.android.internal.widget.remotecompose.core.operations.ColorConstant;
import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
@@ -126,6 +127,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RunActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatExpressionChangeActionOperation;
@@ -233,6 +235,7 @@ public class Operations {
public static final int HAPTIC_FEEDBACK = 177;
public static final int CONDITIONAL_OPERATIONS = 178;
public static final int DEBUG_MESSAGE = 179;
+ public static final int ATTRIBUTE_COLOR = 180;
///////////////////////////////////////// ======================
@@ -287,6 +290,7 @@ public class Operations {
public static final int HOST_ACTION = 209;
public static final int HOST_METADATA_ACTION = 216;
public static final int HOST_NAMED_ACTION = 210;
+ public static final int RUN_ACTION = 236;
public static final int VALUE_INTEGER_CHANGE_ACTION = 212;
public static final int VALUE_STRING_CHANGE_ACTION = 213;
@@ -393,6 +397,7 @@ public class Operations {
map.put(CONTAINER_END, ContainerEnd::read);
+ map.put(RUN_ACTION, RunActionOperation::read);
map.put(HOST_ACTION, HostActionOperation::read);
map.put(HOST_METADATA_ACTION, HostActionMetadataOperation::read);
map.put(HOST_NAMED_ACTION, HostNamedActionOperation::read);
@@ -446,6 +451,7 @@ public class Operations {
map.put(HAPTIC_FEEDBACK, HapticFeedback::read);
map.put(CONDITIONAL_OPERATIONS, ConditionalOperations::read);
map.put(DEBUG_MESSAGE, DebugMessage::read);
+ map.put(ATTRIBUTE_COLOR, ColorAttribute::read);
// map.put(ACCESSIBILITY_CUSTOM_ACTION, CoreSemantics::read);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index e99bce321a8a..dd8790e45761 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
+import java.util.HashMap;
+
/** Specify an abstract paint context used by RemoteCompose commands to draw */
public abstract class PaintContext {
public static final int TEXT_MEASURE_MONOSPACE_WIDTH = 0x01;
@@ -481,28 +483,9 @@ public abstract class PaintContext {
/**
* Starts a graphics layer
*
- * @param scaleX
- * @param scaleY
- * @param rotationX
- * @param rotationY
- * @param rotationZ
- * @param shadowElevation
- * @param transformOriginX
- * @param transformOriginY
- * @param alpha
- * @param renderEffectId
- */
- public abstract void setGraphicsLayer(
- float scaleX,
- float scaleY,
- float rotationX,
- float rotationY,
- float rotationZ,
- float shadowElevation,
- float transformOriginX,
- float transformOriginY,
- float alpha,
- int renderEffectId);
+ * @param attributes
+ */
+ public abstract void setGraphicsLayer(@NonNull HashMap<Integer, Object> attributes);
/** Ends a graphics layer */
public abstract void endGraphicsLayer();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index 5a702c16b521..898e2a8846e3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -25,6 +25,7 @@ import com.android.internal.widget.remotecompose.core.operations.BitmapFontData;
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorAttribute;
import com.android.internal.widget.remotecompose.core.operations.ColorConstant;
import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
@@ -116,6 +117,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RunActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
@@ -132,6 +134,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
/** Provides an abstract buffer to encode/decode RemoteCompose operations */
public class RemoteComposeBuffer {
@@ -2008,55 +2011,10 @@ public class RemoteComposeBuffer {
/**
* Add a graphics layer
*
- * @param scaleX scale x
- * @param scaleY scale y
- * @param rotationX rotation in X
- * @param rotationY rotation in Y
- * @param rotationZ rotation in Z
- * @param shadowElevation shadow elevation
- * @param transformOriginX transform origin x
- * @param transformOriginY transform origin y
- * @param alpha alpha value
- * @param cameraDistance camera distance
- * @param blendMode blend mode
- * @param spotShadowColorId spot shadow color
- * @param ambientShadowColorId ambient shadow color
- * @param colorFilterId id of color filter
- * @param renderEffectId id of render effect
- */
- public void addModifierGraphicsLayer(
- float scaleX,
- float scaleY,
- float rotationX,
- float rotationY,
- float rotationZ,
- float shadowElevation,
- float transformOriginX,
- float transformOriginY,
- float alpha,
- float cameraDistance,
- int blendMode,
- int spotShadowColorId,
- int ambientShadowColorId,
- int colorFilterId,
- int renderEffectId) {
- GraphicsLayerModifierOperation.apply(
- mBuffer,
- scaleX,
- scaleY,
- rotationX,
- rotationY,
- rotationZ,
- shadowElevation,
- transformOriginX,
- transformOriginY,
- alpha,
- cameraDistance,
- blendMode,
- spotShadowColorId,
- ambientShadowColorId,
- colorFilterId,
- renderEffectId);
+ * @param attributes
+ */
+ public void addModifierGraphicsLayer(HashMap<Integer, Object> attributes) {
+ GraphicsLayerModifierOperation.apply(mBuffer, attributes);
}
/**
@@ -2248,6 +2206,11 @@ public class RemoteComposeBuffer {
CanvasOperations.apply(mBuffer);
}
+ /** Add container hosting actions */
+ public void addRunActionsStart() {
+ RunActionOperation.apply(mBuffer);
+ }
+
/**
* Add a component width value
*
@@ -2516,4 +2479,17 @@ public class RemoteComposeBuffer {
public void addDebugMessage(int textId, float value, int flags) {
DebugMessage.apply(mBuffer, textId, value, flags);
}
+
+ /**
+ * Return a color attribute value on the given color
+ *
+ * @param baseColor
+ * @param type type of attribute
+ * @return
+ */
+ public float getColorAttribute(int baseColor, short type) {
+ int id = mRemoteComposeState.nextId();
+ ColorAttribute.apply(mBuffer, id, baseColor, type);
+ return Utils.asNan(id);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index cf229992073c..3c3cad4862c1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -665,6 +665,8 @@ public abstract class RemoteContext {
public static final int ID_EPOCH_SECOND = 32;
+ public static final int ID_FONT_SIZE = 33;
+
public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY);
/** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */
@@ -750,6 +752,9 @@ public abstract class RemoteContext {
/** When was this player built */
public static final float FLOAT_API_LEVEL = Utils.asNan(ID_API_LEVEL);
+ /** The default font size */
+ public static final float FLOAT_FONT_SIZE = Utils.asNan(ID_FONT_SIZE);
+
/** The time in seconds since the epoch. */
public static final long INT_EPOCH_SECOND = ((long) ID_EPOCH_SECOND) + 0x100000000L;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorAttribute.java
new file mode 100644
index 000000000000..8ba5a97f175b
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorAttribute.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2024 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.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+
+import java.util.List;
+
+/** Operation to perform Color related calculation */
+public class ColorAttribute extends PaintOperation {
+ private static final int OP_CODE = Operations.ATTRIBUTE_COLOR;
+ private static final String CLASS_NAME = "ColorAttribute";
+ public int mId;
+ public int mColorId;
+ public short mType;
+
+ /** The hue value of the color */
+ public static final short COLOR_HUE = 0;
+
+ /** The saturation value of the color */
+ public static final short COLOR_SATURATION = 1;
+
+ /** The brightness value of the color */
+ public static final short COLOR_BRIGHTNESS = 2;
+
+ /** The red value of the color */
+ public static final short COLOR_RED = 3;
+
+ /** The green value of the color */
+ public static final short COLOR_GREEN = 4;
+
+ /** The blue value of the color */
+ public static final short COLOR_BLUE = 5;
+
+ /** The alpha value of the color */
+ public static final short COLOR_ALPHA = 6;
+
+ /**
+ * creates a new operation
+ *
+ * @param id to write value to
+ * @param colorId of long to calculate on
+ * @param type the type of calculation
+ */
+ public ColorAttribute(int id, int colorId, short type) {
+ this.mId = id;
+ this.mColorId = colorId;
+ this.mType = type;
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer, mId, mColorId, mType);
+ }
+
+ @Override
+ public @NonNull String toString() {
+ return CLASS_NAME + "[" + mId + "] = " + mColorId + " " + mType;
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ public static @NonNull String name() {
+ return CLASS_NAME;
+ }
+
+ /**
+ * The OP_CODE for this command
+ *
+ * @return the opcode
+ */
+ public static int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ *
+ * @param buffer write command to this buffer
+ * @param id the id
+ * @param textId the id
+ * @param type the value of the float
+ */
+ public static void apply(@NonNull WireBuffer buffer, int id, int textId, short type) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(id);
+ buffer.writeInt(textId);
+ buffer.writeShort(type);
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ int id = buffer.readInt();
+ int textId = buffer.readInt();
+ short type = (short) buffer.readShort();
+ operations.add(new ColorAttribute(id, textId, type));
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Color Operations", OP_CODE, CLASS_NAME)
+ .description("Calculate Information about a Color")
+ .field(INT, "id", "id to output")
+ .field(INT, "longId", "id of color")
+ .field(SHORT, "type", "the type information to extract");
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return indent + toString();
+ }
+
+ @NonNull float[] mBounds = new float[4];
+
+ @Override
+ public void paint(@NonNull PaintContext context) {
+ int val = mType & 255;
+
+ RemoteContext ctx = context.getContext();
+ int color = ctx.getColor(mColorId);
+ switch (val) {
+ case COLOR_HUE:
+ ctx.loadFloat(mId, Utils.getHue(color));
+ break;
+ case COLOR_SATURATION:
+ ctx.loadFloat(mId, Utils.getSaturation(color));
+ break;
+ case COLOR_BRIGHTNESS:
+ ctx.loadFloat(mId, Utils.getBrightness(color));
+ break;
+ case COLOR_RED:
+ ctx.loadFloat(mId, ((color >> 16) & 0xFF) / 255.0f);
+ break;
+ case COLOR_GREEN:
+ ctx.loadFloat(mId, ((color >> 8) & 0xFF) / 255.0f);
+ break;
+ case COLOR_BLUE:
+ ctx.loadFloat(mId, (color & 0xFF) / 255.0f);
+ break;
+ case COLOR_ALPHA:
+ ctx.loadFloat(mId, ((color >> 24) & 0xFF) / 255.0f);
+ break;
+ }
+ }
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer
+ .addType(CLASS_NAME)
+ .add("id", mId)
+ .add("timeId", mColorId)
+ .addType(getTypeString());
+ }
+
+ private String getTypeString() {
+ int val = mType & 255;
+ switch (val) {
+ case COLOR_HUE:
+ return "COLOR_HUE";
+ case COLOR_SATURATION:
+ return "COLOR_SATURATION";
+ case COLOR_BRIGHTNESS:
+ return "COLOR_BRIGHTNESS";
+ case COLOR_RED:
+ return "COLOR_RED";
+ case COLOR_GREEN:
+ return "COLOR_GREEN";
+ case COLOR_BLUE:
+ return "COLOR_BLUE";
+ case COLOR_ALPHA:
+ return "COLOR_ALPHA";
+ default:
+ return "INVALID_TIME_TYPE";
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentData.java
new file mode 100644
index 000000000000..e67482594931
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentData.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2025 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.internal.widget.remotecompose.core.operations;
+
+/** Tagging interface to operations providing data within a component */
+public interface ComponentData {}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
index 20bebaa1ddb2..21d694bf3661 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataListFloat.java
@@ -37,8 +37,8 @@ import java.util.List;
public class DataListFloat extends Operation implements VariableSupport, ArrayAccess, Serializable {
private static final int OP_CODE = Operations.FLOAT_LIST;
private static final String CLASS_NAME = "IdListData";
- private final int mId;
- @NonNull private final float[] mValues;
+ public final int mId;
+ @NonNull private float[] mValues;
private static final int MAX_FLOAT_ARRAY = 2000;
public DataListFloat(int id, @NonNull float[] values) {
@@ -153,4 +153,13 @@ public class DataListFloat extends Operation implements VariableSupport, ArrayAc
public void serialize(MapSerializer serializer) {
serializer.addType(CLASS_NAME).add("id", mId).add("values", List.of(mValues));
}
+
+ /**
+ * Update the DataListFloat with values from a new one
+ *
+ * @param lc
+ */
+ public void update(DataListFloat lc) {
+ mValues = lc.mValues;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index f5c918d89ca5..08ec8baa07d5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -45,7 +45,8 @@ import java.util.List;
* like injecting the width of the component int draw rect As well as supporting generalized
* animation floats. The floats represent a RPN style calculator
*/
-public class FloatExpression extends Operation implements VariableSupport, Serializable {
+public class FloatExpression extends Operation
+ implements ComponentData, VariableSupport, Serializable {
private static final int OP_CODE = Operations.ANIMATED_FLOAT;
private static final String CLASS_NAME = "FloatExpression";
public int mId;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
index 3d6316b67e8f..916eb4d87cbe 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
@@ -87,6 +87,8 @@ public class Header extends Operation implements RemoteComposeOperation {
/** The source of the document */
public static final short DOC_SOURCE = 11;
+ public static final short DOC_DATA_UPDATE = 12;
+
/** The object is an integer */
private static final short DATA_TYPE_INT = 0;
@@ -105,7 +107,8 @@ public class Header extends Operation implements RemoteComposeOperation {
DOC_DENSITY_AT_GENERATION,
DOC_DESIRED_FPS,
DOC_CONTENT_DESCRIPTION,
- DOC_SOURCE
+ DOC_SOURCE,
+ DOC_DATA_UPDATE
};
private static final String[] KEY_NAMES = {
"DOC_WIDTH",
@@ -164,6 +167,9 @@ public class Header extends Operation implements RemoteComposeOperation {
}
private int getInt(int key, int defaultValue) {
+ if (mProperties == null) {
+ return defaultValue;
+ }
Integer value = (Integer) mProperties.get(key);
if (value != null) {
return value;
@@ -173,6 +179,9 @@ public class Header extends Operation implements RemoteComposeOperation {
}
private long getLong(int key, long defaultValue) {
+ if (mProperties == null) {
+ return defaultValue;
+ }
Long value = (Long) mProperties.get(key);
if (value != null) {
return value;
@@ -182,6 +191,9 @@ public class Header extends Operation implements RemoteComposeOperation {
}
private float getFloat(int key, float defaultValue) {
+ if (mProperties == null) {
+ return defaultValue;
+ }
Float value = (Float) mProperties.get(key);
if (value != null) {
return value;
@@ -191,6 +203,9 @@ public class Header extends Operation implements RemoteComposeOperation {
}
private String getString(int key, String defaultValue) {
+ if (mProperties == null) {
+ return defaultValue;
+ }
String value = (String) mProperties.get(key);
if (value != null) {
return value;
@@ -531,6 +546,7 @@ public class Header extends Operation implements RemoteComposeOperation {
* @param document
*/
public void setVersion(CoreDocument document) {
+ document.setUpdateDoc(getInt(DOC_DATA_UPDATE, 0) != 0);
document.setVersion(mMajorVersion, mMinorVersion, mPatchVersion);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index 70197c6d085d..4d9891ba9e49 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -35,7 +35,8 @@ import com.android.internal.widget.remotecompose.core.serialize.Serializable;
import java.util.List;
/** Paint data operation */
-public class PaintData extends PaintOperation implements VariableSupport, Serializable {
+public class PaintData extends PaintOperation
+ implements ComponentData, VariableSupport, Serializable {
private static final int OP_CODE = Operations.PAINT_VALUES;
private static final String CLASS_NAME = "PaintData";
@NonNull public PaintBundle mPaintData = new PaintBundle();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index 3e5dff8ad277..f12c5f004cf0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -47,7 +47,7 @@ import java.util.List;
* animation.
*/
public class TouchExpression extends Operation
- implements VariableSupport, TouchListener, Serializable {
+ implements ComponentData, VariableSupport, TouchListener, Serializable {
private static final int OP_CODE = Operations.TOUCH_EXPRESSION;
private static final String CLASS_NAME = "TouchExpression";
private float mDefValue;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index 5f505409e254..51e7bb273f27 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -306,4 +306,90 @@ public class Utils {
int b = (int) (blue * 255.0f + 0.5f);
return (a << 24 | r << 16 | g << 8 | b);
}
+
+ /**
+ * Returns the hue of an ARGB int
+ *
+ * @param argb the color int
+ * @return
+ */
+ public static float getHue(int argb) {
+ int r = (argb >> 16) & 0xFF;
+ int g = (argb >> 8) & 0xFF;
+ int b = argb & 0xFF;
+ float hsl1, hsl2, hsl3;
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+ final float deltaMaxMin = max - min;
+ float h;
+ if (max == min) {
+ // Monochromatic
+ h = 0f;
+ } else {
+ if (max == rf) {
+ h = ((gf - bf) / deltaMaxMin) % 6f;
+ } else if (max == gf) {
+ h = ((bf - rf) / deltaMaxMin) + 2f;
+ } else {
+ h = ((rf - gf) / deltaMaxMin) + 4f;
+ }
+ }
+ h = (h * 60f) % 360f;
+ if (h < 0) {
+ h += 360f;
+ }
+ return h / 360f;
+ }
+
+ /**
+ * Get the saturation of an ARGB int
+ *
+ * @param argb the color int
+ * @return
+ */
+ public static float getSaturation(int argb) {
+ int r = (argb >> 16) & 0xFF;
+ int g = (argb >> 8) & 0xFF;
+ int b = argb & 0xFF;
+
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+ final float deltaMaxMin = max - min;
+ float s;
+ float l = (max + min) / 2f;
+ if (max == min) {
+ // Monochromatic
+ s = 0f;
+ } else {
+
+ s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
+ }
+
+ return s;
+ }
+
+ /**
+ * Get the brightness of an ARGB int
+ *
+ * @param argb the color int
+ * @return
+ */
+ public static float getBrightness(int argb) {
+ int r = (argb >> 16) & 0xFF;
+ int g = (argb >> 8) & 0xFF;
+ int b = argb & 0xFF;
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+
+ return (max + min) / 2f;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
index bc099e3a3b9d..d33431ee6574 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
@@ -25,12 +25,10 @@ import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.TouchListener;
import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.operations.BitmapData;
-import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.ComponentData;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixSave;
import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate;
-import com.android.internal.widget.remotecompose.core.operations.PaintData;
-import com.android.internal.widget.remotecompose.core.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimationSpec;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentVisibilityOperation;
@@ -48,6 +46,7 @@ import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
import java.util.ArrayList;
+import java.util.HashMap;
/** Component with modifiers and children */
public class LayoutComponent extends Component {
@@ -185,9 +184,7 @@ public class LayoutComponent extends Component {
((ScrollModifierOperation) op).inflate(this);
}
mComponentModifiers.add((ModifierOperation) op);
- } else if (op instanceof TouchExpression
- || (op instanceof PaintData)
- || (op instanceof FloatExpression)) {
+ } else if (op instanceof ComponentData) {
supportedOperations.add(op);
if (op instanceof TouchListener) {
((TouchListener) op).setComponent(this);
@@ -346,6 +343,8 @@ public class LayoutComponent extends Component {
context.restore();
}
+ protected final HashMap<Integer, Object> mCachedAttributes = new HashMap<>();
+
@Override
public void paintingComponent(@NonNull PaintContext context) {
Component prev = context.getContext().mLastComponent;
@@ -359,27 +358,9 @@ public class LayoutComponent extends Component {
}
if (mGraphicsLayerModifier != null) {
context.startGraphicsLayer((int) getWidth(), (int) getHeight());
- float scaleX = mGraphicsLayerModifier.getScaleX();
- float scaleY = mGraphicsLayerModifier.getScaleY();
- float rotationX = mGraphicsLayerModifier.getRotationX();
- float rotationY = mGraphicsLayerModifier.getRotationY();
- float rotationZ = mGraphicsLayerModifier.getRotationZ();
- float shadowElevation = mGraphicsLayerModifier.getShadowElevation();
- float transformOriginX = mGraphicsLayerModifier.getTransformOriginX();
- float transformOriginY = mGraphicsLayerModifier.getTransformOriginY();
- float alpha = mGraphicsLayerModifier.getAlpha();
- int renderEffectId = mGraphicsLayerModifier.getRenderEffectId();
- context.setGraphicsLayer(
- scaleX,
- scaleY,
- rotationX,
- rotationY,
- rotationZ,
- shadowElevation,
- transformOriginX,
- transformOriginY,
- alpha,
- renderEffectId);
+ mCachedAttributes.clear();
+ mGraphicsLayerModifier.fillInAttributes(mCachedAttributes);
+ context.setGraphicsLayer(mCachedAttributes);
}
mComponentModifiers.paint(context);
float tx = mPaddingLeft + getScrollX();
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
index 9afd6d0794eb..09dd842981ec 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
@@ -26,6 +26,8 @@ import com.android.internal.widget.remotecompose.core.operations.layout.measure.
import com.android.internal.widget.remotecompose.core.operations.layout.measure.Measurable;
import com.android.internal.widget.remotecompose.core.operations.layout.measure.MeasurePass;
import com.android.internal.widget.remotecompose.core.operations.layout.measure.Size;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightInModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthInModifierOperation;
/** Base class for layout managers -- resizable components. */
public abstract class LayoutManager extends LayoutComponent implements Measurable {
@@ -292,10 +294,19 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
if (mWidthModifier.isIntrinsicMin()) {
maxWidth = minIntrinsicWidth(context.getContext()) + mPaddingLeft + mPaddingRight;
}
-
if (mHeightModifier.isIntrinsicMin()) {
maxHeight = minIntrinsicHeight(context.getContext()) + mPaddingTop + mPaddingBottom;
}
+ WidthInModifierOperation widthIn = mWidthModifier.getWidthIn();
+ if (widthIn != null) {
+ minWidth = Math.max(minWidth, widthIn.getMin());
+ maxWidth = Math.min(maxWidth, widthIn.getMax());
+ }
+ HeightInModifierOperation heightIn = mHeightModifier.getHeightIn();
+ if (heightIn != null) {
+ minHeight = Math.max(minHeight, heightIn.getMin());
+ maxHeight = Math.min(maxHeight, heightIn.getMax());
+ }
float insetMaxWidth = maxWidth - mPaddingLeft - mPaddingRight;
float insetMaxHeight = maxHeight - mPaddingTop - mPaddingBottom;
@@ -351,10 +362,12 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
if (hasHorizontalWrap) {
measuredWidth = mCachedWrapSize.getWidth();
measuredWidth += mPaddingLeft + mPaddingRight;
+ measuredWidth = Math.max(measuredWidth, minWidth);
}
if (hasVerticalWrap) {
measuredHeight = mCachedWrapSize.getHeight();
measuredHeight += mPaddingTop + mPaddingBottom;
+ measuredHeight = Math.max(measuredHeight, minHeight);
}
} else {
if (hasHorizontalIntrinsicDimension()) {
@@ -377,7 +390,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
context,
0f,
Math.min(measuredWidth, insetMaxWidth),
- 0,
+ 0f,
Math.min(measuredHeight, insetMaxHeight),
measure);
}
@@ -395,14 +408,14 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
context,
0f,
Math.min(measuredWidth, insetMaxWidth),
- 0,
+ 0f,
Math.min(measuredHeight, insetMaxHeight),
measure);
}
} else {
float maxChildWidth = measuredWidth - mPaddingLeft - mPaddingRight;
float maxChildHeight = measuredHeight - mPaddingTop - mPaddingBottom;
- computeSize(context, 0f, maxChildWidth, 0f, maxChildHeight, measure);
+ computeSize(context, 0, maxChildWidth, 0, maxChildHeight, measure);
}
}
@@ -414,6 +427,9 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
cm.setH(measuredHeight);
}
+ measuredWidth = Math.max(measuredWidth, minWidth);
+ measuredHeight = Math.max(measuredHeight, minHeight);
+
ComponentMeasure m = measure.get(this);
m.setW(measuredWidth);
m.setH(measuredHeight);
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index 6f35c3102225..a8e29d957249 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -195,8 +195,18 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
@Override
public void paintingComponent(@NonNull PaintContext context) {
+ Component prev = context.getContext().mLastComponent;
+ RemoteContext remoteContext = context.getContext();
+ remoteContext.mLastComponent = this;
+
context.save();
context.translate(mX, mY);
+ if (mGraphicsLayerModifier != null) {
+ context.startGraphicsLayer((int) getWidth(), (int) getHeight());
+ mCachedAttributes.clear();
+ mGraphicsLayerModifier.fillInAttributes(mCachedAttributes);
+ context.setGraphicsLayer(mCachedAttributes);
+ }
mComponentModifiers.paint(context);
float tx = mPaddingLeft;
float ty = mPaddingTop;
@@ -263,8 +273,13 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
context.restorePaint();
//////////////////////////////////////////////////////////
+ if (mGraphicsLayerModifier != null) {
+ context.endGraphicsLayer();
+ }
+
context.translate(-tx, -ty);
context.restore();
+ context.getContext().mLastComponent = prev;
}
@NonNull
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
index 361438b51a47..05e97eb12248 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
@@ -15,10 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
-import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
-import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
-
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -32,177 +30,228 @@ import com.android.internal.widget.remotecompose.core.operations.utilities.Strin
import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
+import java.util.HashMap;
import java.util.List;
-/**
- * Represents a padding modifier. Padding modifiers can be chained and will impact following
- * modifiers.
- */
+/** Represents a graphics layer modifier. */
public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
private static final int OP_CODE = Operations.MODIFIER_GRAPHICS_LAYER;
public static final String CLASS_NAME = "GraphicsLayerModifierOperation";
- AnimatableValue mScaleX;
- AnimatableValue mScaleY;
- AnimatableValue mRotationX;
- AnimatableValue mRotationY;
- AnimatableValue mRotationZ;
- AnimatableValue mTransformOriginX;
- AnimatableValue mTransformOriginY;
- AnimatableValue mShadowElevation;
- AnimatableValue mAlpha;
- AnimatableValue mCameraDistance;
- int mBlendMode;
- int mSpotShadowColorId;
- int mAmbientShadowColorId;
- int mColorFilterId;
- int mRenderEffectId;
-
- public GraphicsLayerModifierOperation(
- float scaleX,
- float scaleY,
- float rotationX,
- float rotationY,
- float rotationZ,
- float shadowElevation,
- float transformOriginX,
- float transformOriginY,
- float alpha,
- float cameraDistance,
- int blendMode,
- int spotShadowColorId,
- int ambientShadowColorId,
- int colorFilterId,
- int renderEffectId) {
- mScaleX = new AnimatableValue(scaleX);
- mScaleY = new AnimatableValue(scaleY);
- mRotationX = new AnimatableValue(rotationX);
- mRotationY = new AnimatableValue(rotationY);
- mRotationZ = new AnimatableValue(rotationZ);
- mShadowElevation = new AnimatableValue(shadowElevation);
- mTransformOriginX = new AnimatableValue(transformOriginX);
- mTransformOriginY = new AnimatableValue(transformOriginY);
- mAlpha = new AnimatableValue(alpha);
- mCameraDistance = new AnimatableValue(cameraDistance);
- mBlendMode = blendMode;
- mSpotShadowColorId = spotShadowColorId;
- mAmbientShadowColorId = ambientShadowColorId;
- mColorFilterId = colorFilterId;
- mRenderEffectId = renderEffectId;
- }
-
- public float getScaleX() {
- return mScaleX.getValue();
- }
-
- public float getScaleY() {
- return mScaleY.getValue();
- }
-
- public float getRotationX() {
- return mRotationX.getValue();
- }
-
- public float getRotationY() {
- return mRotationY.getValue();
- }
-
- public float getRotationZ() {
- return mRotationZ.getValue();
- }
-
- public float getShadowElevation() {
- return mShadowElevation.getValue();
- }
-
- public float getTransformOriginX() {
- return mTransformOriginX.getValue();
- }
-
- public float getTransformOriginY() {
- return mTransformOriginY.getValue();
- }
-
- public float getAlpha() {
- return mAlpha.getValue();
- }
-
- public float getCameraDistance() {
- return mCameraDistance.getValue();
- }
-
- // TODO: add implementation for blendmode
- public int getBlendModeId() {
- return mBlendMode;
- }
-
- // TODO: add implementation for shadow
- public int getSpotShadowColorId() {
- return mSpotShadowColorId;
- }
+ public static final int SCALE_X = 0;
+ public static final int SCALE_Y = 1;
+ public static final int ROTATION_X = 2;
+ public static final int ROTATION_Y = 3;
+ public static final int ROTATION_Z = 4;
+ public static final int TRANSFORM_ORIGIN_X = 5;
+ public static final int TRANSFORM_ORIGIN_Y = 6;
+ public static final int TRANSLATION_X = 7;
+ public static final int TRANSLATION_Y = 8;
+ public static final int TRANSLATION_Z = 9;
+ public static final int SHADOW_ELEVATION = 10;
+ public static final int ALPHA = 11;
+ public static final int CAMERA_DISTANCE = 12;
+ public static final int COMPOSITING_STRATEGY = 13;
+ public static final int SPOT_SHADOW_COLOR = 14;
+ public static final int AMBIENT_SHADOW_COLOR = 15;
+ public static final int HAS_BLUR = 16;
+ public static final int BLUR_RADIUS_X = 17;
+ public static final int BLUR_RADIUS_Y = 18;
+ public static final int BLUR_TILE_MODE = 19;
+ public static final int SHAPE = 20;
+ public static final int SHAPE_RADIUS = 21;
+
+ public static final int SHAPE_RECT = 0;
+ public static final int SHAPE_ROUND_RECT = 1;
+ public static final int SHAPE_CIRCLE = 2;
+
+ public static final int TILE_MODE_CLAMP = 0;
+ public static final int TILE_MODE_REPEATED = 1;
+ public static final int TILE_MODE_MIRROR = 2;
+ public static final int TILE_MODE_DECAL = 3;
+
+ /** The object is an integer */
+ private static final short DATA_TYPE_INT = 0;
+
+ /** The object is an float */
+ private static final short DATA_TYPE_FLOAT = 1;
+
+ AttributeValue[] mValues = {
+ new AttributeValue(SCALE_X, "SCALE_X", 1f),
+ new AttributeValue(SCALE_Y, "SCALE_Y", 1f),
+ new AttributeValue(ROTATION_X, "ROTATION_X", 0f),
+ new AttributeValue(ROTATION_Y, "ROTATION_Y", 0f),
+ new AttributeValue(ROTATION_Z, "ROTATION_Z", 0f),
+ new AttributeValue(TRANSFORM_ORIGIN_X, "TRANSFORM_ORIGIN_X", 0f),
+ new AttributeValue(TRANSFORM_ORIGIN_Y, "TRANSFORM_ORIGIN_Y", 0f),
+ new AttributeValue(TRANSLATION_X, "TRANSLATION_X", 0f),
+ new AttributeValue(TRANSLATION_Y, "TRANSLATION_Y", 0f),
+ new AttributeValue(TRANSLATION_Z, "TRANSLATION_Z", 0f),
+ new AttributeValue(SHADOW_ELEVATION, "SHADOW_ELEVATION", 0f),
+ new AttributeValue(ALPHA, "ALPHA", 1f),
+ new AttributeValue(CAMERA_DISTANCE, "CAMERA_DISTANCE", 8f),
+ new AttributeValue(COMPOSITING_STRATEGY, "COMPOSITING_STRATEGY", 0),
+ new AttributeValue(SPOT_SHADOW_COLOR, "SPOT_SHADOW_COLOR", 0),
+ new AttributeValue(AMBIENT_SHADOW_COLOR, "AMBIENT_SHADOW_COLOR", 0),
+ new AttributeValue(HAS_BLUR, "HAS_BLUR", 0),
+ new AttributeValue(BLUR_RADIUS_X, "BLUR_RADIUS_X", 0f),
+ new AttributeValue(BLUR_RADIUS_Y, "BLUR_RADIUS_Y", 0f),
+ new AttributeValue(BLUR_TILE_MODE, "BLUR_TILE_MODE", TILE_MODE_CLAMP),
+ new AttributeValue(SHAPE, "SHAPE", -1),
+ new AttributeValue(SHAPE_RADIUS, "SHAPE_RADIUS", 0f),
+ };
+
+ boolean mHasBlurEffect = false;
- public int getAmbientShadowColorId() {
- return mAmbientShadowColorId;
- }
-
- // TODO: add implementation for color filters
- public int getColorFilterId() {
- return mColorFilterId;
+ /**
+ * Fill in the hashmap with the attributes values
+ *
+ * @param attributes
+ */
+ public void fillInAttributes(HashMap<Integer, Object> attributes) {
+ for (int i = 0; i < mValues.length; i++) {
+ if (mValues[i].needsToWrite()) {
+ attributes.put(i, mValues[i].getObjectValue());
+ }
+ }
}
- public int getRenderEffectId() {
- return mRenderEffectId;
+ static final int FLOAT_VALUE = 0;
+ static final int INT_VALUE = 1;
+
+ /** Utility class to manage attributes */
+ static class AttributeValue {
+ String mName;
+ int mId;
+ @Nullable AnimatableValue mAnimatableValue;
+ float mDefaultValue = 0f;
+ int mIntValue = 0;
+ int mIntDefaultValue = 0;
+ int mType = FLOAT_VALUE;
+
+ AttributeValue(int id, String name, float defaultValue) {
+ mId = id;
+ mName = name;
+ mDefaultValue = defaultValue;
+ mType = FLOAT_VALUE;
+ }
+
+ AttributeValue(int id, String name, int defaultValue) {
+ mId = id;
+ mName = name;
+ mIntDefaultValue = defaultValue;
+ mType = INT_VALUE;
+ }
+
+ public float getValue() {
+ if (mType == FLOAT_VALUE) {
+ if (mAnimatableValue != null) {
+ return mAnimatableValue.getValue();
+ }
+ return mDefaultValue;
+ } else {
+ return mIntValue;
+ }
+ }
+
+ public int getIntValue() {
+ if (mType == FLOAT_VALUE) {
+ if (mAnimatableValue != null) {
+ return (int) mAnimatableValue.getValue();
+ }
+ } else if (mType == INT_VALUE) {
+ return mIntValue;
+ }
+ return 0;
+ }
+
+ public void evaluate(PaintContext context) {
+ if (mAnimatableValue != null) {
+ mAnimatableValue.evaluate(context);
+ }
+ }
+
+ public boolean needsToWrite() {
+ if (mType == FLOAT_VALUE) {
+ if (mAnimatableValue != null) {
+ return mAnimatableValue.getValue() != mDefaultValue;
+ }
+ return false;
+ } else if (mType == INT_VALUE) {
+ return mIntValue != mIntDefaultValue;
+ }
+ return false;
+ }
+
+ public void write(WireBuffer buffer) {
+ buffer.writeInt(mId);
+ if (mType == FLOAT_VALUE) {
+ buffer.writeFloat(getValue());
+ } else if (mType == INT_VALUE) {
+ buffer.writeInt(getIntValue());
+ }
+ }
+
+ public Object getObjectValue() {
+ if (mType == FLOAT_VALUE) {
+ return getValue();
+ }
+ return getIntValue();
+ }
+
+ public void setValue(float value) {
+ mAnimatableValue = new AnimatableValue(value);
+ }
+
+ public void setValue(int value) {
+ mIntValue = value;
+ }
}
@Override
- public void write(WireBuffer buffer) {
- apply(
- buffer,
- mScaleX.getValue(),
- mScaleY.getValue(),
- mRotationX.getValue(),
- mRotationY.getValue(),
- mRotationZ.getValue(),
- mShadowElevation.getValue(),
- mTransformOriginX.getValue(),
- mTransformOriginY.getValue(),
- mAlpha.getValue(),
- mCameraDistance.getValue(),
- mBlendMode,
- mSpotShadowColorId,
- mAmbientShadowColorId,
- mColorFilterId,
- mRenderEffectId);
+ public void write(@NonNull WireBuffer buffer) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(mValues.length);
+ for (int i = 0; i < mValues.length; i++) {
+ AttributeValue value = mValues[i];
+ if (value.needsToWrite()) {
+ value.write(buffer);
+ }
+ }
}
@Override
public void serializeToString(int indent, StringSerializer serializer) {
- serializer.append(indent, "GRAPHICS_LAYER = [" + mScaleX + ", " + mScaleY + "]");
+ serializer.append(
+ indent,
+ "GRAPHICS_LAYER = ["
+ + mValues[SCALE_X].getValue()
+ + ", "
+ + mValues[SCALE_Y].getValue()
+ + "]");
}
@NonNull
@Override
public String deepToString(@NonNull String indent) {
- return (indent != null ? indent : "") + toString();
+ return indent + toString();
}
@Override
- public void paint(PaintContext context) {
- mScaleX.evaluate(context);
- mScaleY.evaluate(context);
- mRotationX.evaluate(context);
- mRotationY.evaluate(context);
- mRotationZ.evaluate(context);
- mTransformOriginX.evaluate(context);
- mTransformOriginY.evaluate(context);
- mShadowElevation.evaluate(context);
- mAlpha.evaluate(context);
- mCameraDistance.evaluate(context);
+ public void paint(@NonNull PaintContext context) {
+ for (int i = 0; i < mValues.length; i++) {
+ AttributeValue v = mValues[i];
+ v.evaluate(context);
+ }
}
@Override
public String toString() {
- return "GraphicsLayerModifierOperation(" + mScaleX + ", " + mScaleY + ")";
+ return "GraphicsLayerModifierOperation("
+ + mValues[SCALE_X].getValue()
+ + ", "
+ + mValues[SCALE_Y].getValue()
+ + ")";
}
/**
@@ -228,55 +277,46 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
* Write the operation to the buffer
*
* @param buffer a WireBuffer
- * @param scaleX scaleX of the layer
- * @param scaleY scaleY of the layer
- * @param rotationX rotationX of the layer
- * @param rotationY rotationY of the layer
- * @param rotationZ rotationZ of the layer
- * @param shadowElevation the shadow elevation
- * @param transformOriginX the X origin of the transformations
- * @param transformOriginY the Y origin of the transformations
- * @param alpha the alpha of the layer
- * @param cameraDistance the camera distance
- * @param blendMode blending mode of the layer
- * @param spotShadowColorId the spot shadow color id
- * @param ambientShadowColorId the ambient shadow color id
- * @param colorFilterId the color filter id
- * @param renderEffectId the render effect id
+ * @param values attributes of the layer
*/
- public static void apply(
- WireBuffer buffer,
- float scaleX,
- float scaleY,
- float rotationX,
- float rotationY,
- float rotationZ,
- float shadowElevation,
- float transformOriginX,
- float transformOriginY,
- float alpha,
- float cameraDistance,
- int blendMode,
- int spotShadowColorId,
- int ambientShadowColorId,
- int colorFilterId,
- int renderEffectId) {
+ public static void apply(WireBuffer buffer, HashMap<Integer, Object> values) {
buffer.start(OP_CODE);
- buffer.writeFloat(scaleX);
- buffer.writeFloat(scaleY);
- buffer.writeFloat(rotationX);
- buffer.writeFloat(rotationY);
- buffer.writeFloat(rotationZ);
- buffer.writeFloat(shadowElevation);
- buffer.writeFloat(transformOriginX);
- buffer.writeFloat(transformOriginY);
- buffer.writeFloat(alpha);
- buffer.writeFloat(cameraDistance);
- buffer.writeInt(blendMode);
- buffer.writeInt(spotShadowColorId);
- buffer.writeInt(ambientShadowColorId);
- buffer.writeInt(colorFilterId);
- buffer.writeInt(renderEffectId);
+ int size = values.size();
+ buffer.writeInt(size);
+ for (Integer key : values.keySet()) {
+ Object value = values.get(key);
+ if (value instanceof Integer) {
+ writeIntAttribute(buffer, key, (Integer) value);
+ } else if (value instanceof Float) {
+ writeFloatAttribute(buffer, key, (Float) value);
+ }
+ }
+ }
+
+ /**
+ * Utility to write an integer attribute
+ *
+ * @param buffer
+ * @param type
+ * @param value
+ */
+ private static void writeIntAttribute(WireBuffer buffer, int type, int value) {
+ int tag = type | (DATA_TYPE_INT << 10);
+ buffer.writeInt(tag);
+ buffer.writeInt(value);
+ }
+
+ /**
+ * Utility to write a float attribute
+ *
+ * @param buffer
+ * @param type
+ * @param value
+ */
+ private static void writeFloatAttribute(WireBuffer buffer, int type, float value) {
+ int tag = type | (DATA_TYPE_FLOAT << 10);
+ buffer.writeInt(tag);
+ buffer.writeFloat(value);
}
/**
@@ -286,38 +326,34 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
* @param operations the list of operations read so far
*/
public static void read(WireBuffer buffer, List<Operation> operations) {
- float scaleX = buffer.readFloat();
- float scaleY = buffer.readFloat();
- float rotationX = buffer.readFloat();
- float rotationY = buffer.readFloat();
- float rotationZ = buffer.readFloat();
- float shadowElevation = buffer.readFloat();
- float transformOriginX = buffer.readFloat();
- float transformOriginY = buffer.readFloat();
- float alpha = buffer.readFloat();
- float cameraDistance = buffer.readFloat();
- int blendMode = buffer.readInt();
- int spotShadowColorId = buffer.readInt();
- int ambientShadowColorId = buffer.readInt();
- int colorFilterId = buffer.readInt();
- int renderEffectId = buffer.readInt();
- operations.add(
- new GraphicsLayerModifierOperation(
- scaleX,
- scaleY,
- rotationX,
- rotationY,
- rotationZ,
- shadowElevation,
- transformOriginX,
- transformOriginY,
- alpha,
- cameraDistance,
- blendMode,
- spotShadowColorId,
- ambientShadowColorId,
- colorFilterId,
- renderEffectId));
+ int length = buffer.readInt();
+ GraphicsLayerModifierOperation op = new GraphicsLayerModifierOperation();
+ for (int i = 0; i < length; i++) {
+ op.readAttributeValue(buffer);
+ }
+ operations.add(op);
+ }
+
+ /**
+ * Read a single attribute value from the buffer
+ *
+ * @param buffer
+ */
+ private void readAttributeValue(WireBuffer buffer) {
+ int tag = buffer.readInt();
+ int dataType = tag >> 10;
+ int index = (short) (tag & 0x3F);
+ if (index == BLUR_RADIUS_X || index == BLUR_RADIUS_Y) {
+ mHasBlurEffect = true;
+ mValues[HAS_BLUR].setValue(1);
+ }
+ if (dataType == DATA_TYPE_FLOAT) {
+ float value = buffer.readFloat();
+ mValues[index].setValue(value);
+ } else if (dataType == DATA_TYPE_INT) {
+ int value = buffer.readInt();
+ mValues[index].setValue(value);
+ }
}
/**
@@ -327,22 +363,7 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
*/
public static void documentation(DocumentationBuilder doc) {
doc.operation("Modifier Operations", OP_CODE, CLASS_NAME)
- .description("define the GraphicsLayer Modifier")
- .field(FLOAT, "scaleX", "")
- .field(FLOAT, "scaleY", "")
- .field(FLOAT, "rotationX", "")
- .field(FLOAT, "rotationY", "")
- .field(FLOAT, "rotationZ", "")
- .field(FLOAT, "shadowElevation", "")
- .field(FLOAT, "transformOriginX", "")
- .field(FLOAT, "transformOriginY", "")
- .field(FLOAT, "alpha", "")
- .field(FLOAT, "cameraDistance", "")
- .field(INT, "blendMode", "")
- .field(INT, "spotShadowColorId", "")
- .field(INT, "ambientShadowColorId", "")
- .field(INT, "colorFilterId", "")
- .field(INT, "renderEffectId", "");
+ .description("define the GraphicsLayer Modifier");
}
@Override
@@ -353,20 +374,21 @@ public class GraphicsLayerModifierOperation extends DecoratorModifierOperation {
serializer
.addTags(SerializeTags.MODIFIER)
.addType("GraphicsLayerModifierOperation")
- .add("scaleX", mScaleX)
- .add("scaleX", mScaleX)
- .add("rotationX", mRotationX)
- .add("rotationY", mRotationY)
- .add("rotationZ", mRotationZ)
- .add("shadowElevation", mShadowElevation)
- .add("transformOriginX", mTransformOriginX)
- .add("transformOriginY", mTransformOriginY)
- .add("alpha", mAlpha)
- .add("cameraDistance", mCameraDistance)
- .add("blendMode", mBlendMode)
- .add("spotShadowColorId", mSpotShadowColorId)
- .add("ambientShadowColorId", mAmbientShadowColorId)
- .add("colorFilterId", mColorFilterId)
- .add("renderEffectId", mRenderEffectId);
+ .add("scaleX", mValues[SCALE_X].getValue())
+ .add("scaleY", mValues[SCALE_Y].getValue())
+ .add("rotationX", mValues[ROTATION_X].getValue())
+ .add("rotationY", mValues[ROTATION_Y].getValue())
+ .add("rotationZ", mValues[ROTATION_Z].getValue())
+ .add("shadowElevation", mValues[SHADOW_ELEVATION].getValue())
+ .add("transformOriginX", mValues[TRANSFORM_ORIGIN_X].getValue())
+ .add("transformOriginY", mValues[TRANSFORM_ORIGIN_Y].getValue())
+ .add("translationX", mValues[TRANSLATION_X].getValue())
+ .add("translationY", mValues[TRANSLATION_Y].getValue())
+ .add("translationZ", mValues[TRANSLATION_Z].getValue())
+ .add("alpha", mValues[ALPHA].getValue())
+ .add("cameraDistance", mValues[CAMERA_DISTANCE].getValue())
+ .add("compositingStrategy", mValues[COMPOSITING_STRATEGY].getIntValue())
+ .add("spotShadowColorId", mValues[SPOT_SHADOW_COLOR].getIntValue())
+ .add("ambientShadowColorId", mValues[AMBIENT_SHADOW_COLOR].getIntValue());
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RunActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RunActionOperation.java
new file mode 100644
index 000000000000..049c004a9c19
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RunActionOperation.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.internal.widget.remotecompose.core.operations.layout.modifiers;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.ActionOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.Container;
+import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Contains actions and immediately runs them */
+public class RunActionOperation extends PaintOperation implements Container {
+ private static final int OP_CODE = Operations.RUN_ACTION;
+ private static final String CLASS_NAME = "RunActionOperation";
+
+ @NonNull public ArrayList<Operation> mList = new ArrayList<>();
+
+ public RunActionOperation() {}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "RunActionOperation()";
+ }
+
+ /**
+ * The returns a list to be filled
+ *
+ * @return list to be filled
+ */
+ @NonNull
+ public ArrayList<Operation> getList() {
+ return mList;
+ }
+
+ /**
+ * Returns the serialized name for this operation
+ *
+ * @return the serialized name
+ */
+ @NonNull
+ public String serializedName() {
+ return "RUN_ACTION";
+ }
+
+ @Override
+ public void serialize(MapSerializer serializer) {
+ serializer.addType(CLASS_NAME).add("list", mList);
+ }
+
+ @Override
+ public void paint(@NonNull PaintContext context) {
+ CoreDocument document = context.getContext().getDocument();
+ Component component = context.getContext().mLastComponent;
+ if (document == null || component == null) {
+ return;
+ }
+ for (Operation op : getList()) {
+ if (op instanceof ActionOperation) {
+ ActionOperation actionOperation = (ActionOperation) op;
+ actionOperation.runAction(context.getContext(), document, component, 0f, 0f);
+ }
+ }
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public boolean isDirty() {
+ // Always execute
+ return true;
+ }
+
+ @Override
+ public void markNotDirty() {
+ // nothing
+ }
+
+ @Override
+ public void markDirty() {
+ // nothing
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer);
+ }
+
+ /**
+ * Write the operation to the buffer
+ *
+ * @param buffer a WireBuffer
+ */
+ public static void apply(@NonNull WireBuffer buffer) {
+ buffer.start(OP_CODE);
+ }
+
+ /**
+ * Read this operation and add it to the list of operations
+ *
+ * @param buffer the buffer to read
+ * @param operations the list of operations that will be added to
+ */
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ operations.add(new RunActionOperation());
+ }
+
+ /**
+ * Populate the documentation with a description of this operation
+ *
+ * @param doc to append the description to.
+ */
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Operations", OP_CODE, "RunAction")
+ .description("This operation runs child actions");
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
index 2a3f3be714b9..e1a5a49d1fa9 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
@@ -146,4 +146,8 @@ public class RemoteComposeDocument {
return 0;
}
+
+ public boolean isUpdateDoc() {
+ return mDocument.isUpdateDoc();
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 682559a4a9b4..510e4c4cc2c6 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -137,6 +137,10 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
if (value != null) {
if (value.canBeDisplayed(
MAX_SUPPORTED_MAJOR_VERSION, MAX_SUPPORTED_MINOR_VERSION, 0L)) {
+ if (value.isUpdateDoc()) {
+ updateDocument(value);
+ return;
+ }
mInner.setDocument(value);
int contentBehavior = value.getDocument().getContentScroll();
applyContentBehavior(contentBehavior);
@@ -150,6 +154,7 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
RemoteComposeTouchHelper.REGISTRAR.clearAccessibilityDelegate(this);
}
+
mapColors();
setupSensors();
mInner.setHapticEngine(
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index 86946379dae7..f60905db9c4d 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -23,6 +23,7 @@ import android.graphics.BitmapShader;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
@@ -48,10 +49,12 @@ import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.TextLayout;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintChanges;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/**
@@ -144,31 +147,127 @@ public class AndroidPaintContext extends PaintContext {
}
@Override
- public void setGraphicsLayer(
- float scaleX,
- float scaleY,
- float rotationX,
- float rotationY,
- float rotationZ,
- float shadowElevation,
- float transformOriginX,
- float transformOriginY,
- float alpha,
- int renderEffectId) {
+ public void setGraphicsLayer(@NonNull HashMap<Integer, Object> attributes) {
if (mNode == null) {
return;
}
- mNode.setScaleX(scaleX);
- mNode.setScaleY(scaleY);
- mNode.setRotationX(rotationX);
- mNode.setRotationY(rotationY);
- mNode.setRotationZ(rotationZ);
- mNode.setPivotX(transformOriginX * mNode.getWidth());
- mNode.setPivotY(transformOriginY * mNode.getHeight());
- mNode.setAlpha(alpha);
- if (renderEffectId == 1) {
-
- RenderEffect effect = RenderEffect.createBlurEffect(8f, 8f, Shader.TileMode.CLAMP);
+ boolean hasBlurEffect = false;
+ boolean hasOutline = false;
+ for (Integer key : attributes.keySet()) {
+ Object value = attributes.get(key);
+ switch (key) {
+ case GraphicsLayerModifierOperation.SCALE_X:
+ mNode.setScaleX((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.SCALE_Y:
+ mNode.setScaleY((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.ROTATION_X:
+ mNode.setRotationX((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.ROTATION_Y:
+ mNode.setRotationY((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.ROTATION_Z:
+ mNode.setRotationZ((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.TRANSFORM_ORIGIN_X:
+ mNode.setPivotX((Float) value * mNode.getWidth());
+ break;
+ case GraphicsLayerModifierOperation.TRANSFORM_ORIGIN_Y:
+ mNode.setPivotY((Float) value * mNode.getWidth());
+ break;
+ case GraphicsLayerModifierOperation.TRANSLATION_X:
+ mNode.setTranslationX((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.TRANSLATION_Y:
+ mNode.setTranslationY((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.TRANSLATION_Z:
+ mNode.setTranslationZ((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.SHAPE:
+ hasOutline = true;
+ break;
+ case GraphicsLayerModifierOperation.SHADOW_ELEVATION:
+ mNode.setElevation((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.ALPHA:
+ mNode.setAlpha((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.CAMERA_DISTANCE:
+ mNode.setCameraDistance((Float) value);
+ break;
+ case GraphicsLayerModifierOperation.SPOT_SHADOW_COLOR:
+ mNode.setSpotShadowColor((Integer) value);
+ break;
+ case GraphicsLayerModifierOperation.AMBIENT_SHADOW_COLOR:
+ mNode.setAmbientShadowColor((Integer) value);
+ break;
+ case GraphicsLayerModifierOperation.HAS_BLUR:
+ hasBlurEffect = ((Integer) value) != 0;
+ break;
+ }
+ }
+ if (hasOutline) {
+ Outline outline = new Outline();
+ outline.setAlpha(1f);
+ Object oShape = attributes.get(GraphicsLayerModifierOperation.SHAPE);
+ if (oShape != null) {
+ Object oShapeRadius = attributes.get(GraphicsLayerModifierOperation.SHAPE_RADIUS);
+ int type = (Integer) oShape;
+ if (type == GraphicsLayerModifierOperation.SHAPE_RECT) {
+ outline.setRect(0, 0, mNode.getWidth(), mNode.getHeight());
+ } else if (type == GraphicsLayerModifierOperation.SHAPE_ROUND_RECT) {
+ if (oShapeRadius != null) {
+ float radius = (Float) oShapeRadius;
+ outline.setRoundRect(
+ new Rect(0, 0, mNode.getWidth(), mNode.getHeight()), radius);
+ } else {
+ outline.setRect(0, 0, mNode.getWidth(), mNode.getHeight());
+ }
+ } else if (type == GraphicsLayerModifierOperation.SHAPE_CIRCLE) {
+ float radius = Math.min(mNode.getWidth(), mNode.getHeight()) / 2f;
+ outline.setRoundRect(
+ new Rect(0, 0, mNode.getWidth(), mNode.getHeight()), radius);
+ }
+ }
+ mNode.setOutline(outline);
+ }
+ if (hasBlurEffect) {
+ Object oBlurRadiusX = attributes.get(GraphicsLayerModifierOperation.BLUR_RADIUS_X);
+ float blurRadiusX = 0f;
+ if (oBlurRadiusX != null) {
+ blurRadiusX = (Float) oBlurRadiusX;
+ }
+ Object oBlurRadiusY = attributes.get(GraphicsLayerModifierOperation.BLUR_RADIUS_Y);
+ float blurRadiusY = 0f;
+ if (oBlurRadiusY != null) {
+ blurRadiusY = (Float) oBlurRadiusY;
+ }
+ int blurTileMode = 0;
+ Object oBlurTileMode = attributes.get(GraphicsLayerModifierOperation.BLUR_TILE_MODE);
+ if (oBlurTileMode != null) {
+ blurTileMode = (Integer) oBlurTileMode;
+ }
+ Shader.TileMode tileMode = Shader.TileMode.CLAMP;
+ switch (blurTileMode) {
+ case GraphicsLayerModifierOperation.TILE_MODE_CLAMP:
+ tileMode = Shader.TileMode.CLAMP;
+ break;
+ case GraphicsLayerModifierOperation.TILE_MODE_DECAL:
+ tileMode = Shader.TileMode.DECAL;
+
+ break;
+ case GraphicsLayerModifierOperation.TILE_MODE_MIRROR:
+ tileMode = Shader.TileMode.MIRROR;
+ break;
+ case GraphicsLayerModifierOperation.TILE_MODE_REPEATED:
+ tileMode = Shader.TileMode.REPEAT;
+ break;
+ }
+
+ RenderEffect effect = RenderEffect.createBlurEffect(blurRadiusX, blurRadiusY, tileMode);
mNode.setRenderEffect(effect);
}
}
@@ -177,7 +276,11 @@ public class AndroidPaintContext extends PaintContext {
public void endGraphicsLayer() {
mNode.endRecording();
mCanvas = mPreviousCanvas;
- mCanvas.drawRenderNode(mNode);
+ if (mCanvas.isHardwareAccelerated()) {
+ mCanvas.enableZ();
+ mCanvas.drawRenderNode(mNode);
+ mCanvas.disableZ();
+ }
// node.discardDisplayList();
mNode = null;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index 3d728c37d5bf..4dc664612b87 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -28,6 +28,7 @@ import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.TextView;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.RemoteContext;
@@ -117,6 +118,8 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
updateClickAreas();
requestLayout();
mARContext.loadFloat(RemoteContext.ID_TOUCH_EVENT_TIME, -Float.MAX_VALUE);
+ mARContext.loadFloat(RemoteContext.ID_FONT_SIZE, getDefaultTextSize());
+
invalidate();
Integer fps = (Integer) mDocument.getDocument().getProperty(Header.DOC_DESIRED_FPS);
if (fps != null && fps > 0) {
@@ -255,6 +258,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
/**
* Set a local named color
+ *
* @param name
* @param content
*/
@@ -267,6 +271,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
/**
* Clear a local named color
+ *
* @param name
*/
public void clearLocalColor(String name) {
@@ -642,4 +647,8 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
canvas.drawText(str, x, y, paint);
}
+
+ private float getDefaultTextSize() {
+ return new TextView(getContext()).getTextSize();
+ }
}