summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-04-09 18:36:32 -0700
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-04-09 18:36:32 -0700
commitea39268231d379acaf5ed243ea64f5ba37c638c3 (patch)
treee8f5a908364277300d0146557fbfde73519adfee
parent9fe1eb72ce6342f8fb88201fa42db3a7ef8539ee (diff)
parent03c576b78ba829e98efcc3aa32903e42fcabf251 (diff)
Merge cherrypicks of ['googleplex-android-review.googlesource.com/32772320', 'googleplex-android-review.googlesource.com/32888719'] into 25Q2-release.
Change-Id: Iab3b5b1fd7f0832d9d450ab69d17df488736a113
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java115
-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.java39
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java76
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java17
-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/ConditionalOperations.java5
-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/DrawBitmapFontText.java6
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java32
-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/LoopOperation.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java5
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java182
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java17
-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/core/operations/paint/PaintBundle.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java4
-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.java63
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java152
-rw-r--r--core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java32
29 files changed, 1394 insertions, 443 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 d62538b6d1ed..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;
@@ -64,16 +64,16 @@ public class CoreDocument implements Serializable {
private static final boolean DEBUG = false;
// Semantic version
- public static final int MAJOR_VERSION = 0;
- public static final int MINOR_VERSION = 4;
+ public static final int MAJOR_VERSION = 1;
+ public static final int MINOR_VERSION = 0;
public static final int PATCH_VERSION = 0;
// Internal version level
- public static final int DOCUMENT_API_LEVEL = 4;
+ 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
- static final float BUILD = 0.8f;
+ static final float BUILD = 0.0f;
private static final boolean UPDATE_VARIABLES_BEFORE_LAYOUT = false;
@@ -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);
}
@@ -640,6 +651,32 @@ public class CoreDocument implements Serializable {
this.minor = minor;
this.patchLevel = patchLevel;
}
+
+ /**
+ * Returns true if the document has been encoded for at least the given version MAJOR.MINOR
+ *
+ * @param major major version number
+ * @param minor minor version number
+ * @param patch patch version number
+ * @return true if the document was written at least with the given version
+ */
+ public boolean supportsVersion(int major, int minor, int patch) {
+ if (major > this.major) {
+ return false;
+ }
+ if (major < this.major) {
+ return true;
+ }
+ // major is the same
+ if (minor > this.minor) {
+ return false;
+ }
+ if (minor < this.minor) {
+ return true;
+ }
+ // minor is the same
+ return patch <= this.patchLevel;
+ }
}
public static class ClickAreaRepresentation {
@@ -935,12 +972,20 @@ public class CoreDocument implements Serializable {
/**
* Returns true if the document can be displayed given this version of the player
*
- * @param majorVersion the max major version supported by the player
- * @param minorVersion the max minor version supported by the player
+ * @param playerMajorVersion the max major version supported by the player
+ * @param playerMinorVersion the max minor version supported by the player
* @param capabilities a bitmask of capabilities the player supports (unused for now)
*/
- public boolean canBeDisplayed(int majorVersion, int minorVersion, long capabilities) {
- return mVersion.major <= majorVersion && mVersion.minor <= minorVersion;
+ public boolean canBeDisplayed(
+ int playerMajorVersion, int playerMinorVersion, long capabilities) {
+ if (mVersion.major < playerMajorVersion) {
+ return true;
+ }
+ if (mVersion.major > playerMajorVersion) {
+ return false;
+ }
+ // same major version
+ return mVersion.minor <= playerMinorVersion;
}
/**
@@ -1182,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;
}
//////////////////////////////////////////////////////////////////////////
@@ -1543,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 e61ca4c1ee13..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();
@@ -518,4 +501,16 @@ public abstract class PaintContext {
* @return the string if found
*/
public abstract @Nullable String getText(int textID);
+
+ /**
+ * Returns true if the document has been encoded for at least the given version MAJOR.MINOR
+ *
+ * @param major major version number
+ * @param minor minor version number
+ * @param patch patch version number
+ * @return true if the document was written at least with the given version
+ */
+ public boolean supportsVersion(int major, int minor, int patch) {
+ return mContext.supportsVersion(major, minor, patch);
+ }
}
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 eb7399afd2b7..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 {
@@ -1333,7 +1336,7 @@ public class RemoteComposeBuffer {
* @return the nan id of float
*/
public float reserveFloatVariable() {
- int id = mRemoteComposeState.cacheFloat(0f);
+ int id = mRemoteComposeState.nextId();
return Utils.asNan(id);
}
@@ -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 b297a023d03b..3c3cad4862c1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -68,6 +68,18 @@ public abstract class RemoteContext {
private boolean mUseChoreographer = true;
+ /**
+ * Returns true if the document has been encoded for at least the given version MAJOR.MINOR
+ *
+ * @param major major version number
+ * @param minor minor version number
+ * @param patch patch version number
+ * @return true if the document was written at least with the given version
+ */
+ public boolean supportsVersion(int major, int minor, int patch) {
+ return mDocument.mVersion.supportsVersion(major, minor, patch);
+ }
+
public float getDensity() {
return mDensity;
}
@@ -653,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 */
@@ -738,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/ConditionalOperations.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java
index da6035e1e87e..a288142cef8d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ConditionalOperations.java
@@ -83,6 +83,11 @@ public class ConditionalOperations extends PaintOperation
public void updateVariables(RemoteContext context) {
mVarAOut = Float.isNaN(mVarA) ? context.getFloat(Utils.idFromNan(mVarA)) : mVarA;
mVarBOut = Float.isNaN(mVarB) ? context.getFloat(Utils.idFromNan(mVarB)) : mVarB;
+ for (Operation op : mList) {
+ if (op instanceof VariableSupport && op.isDirty()) {
+ ((VariableSupport) op).updateVariables(context);
+ }
+ }
}
/**
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/DrawBitmapFontText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
index bff87fda2fd9..87a99343c28c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapFontText.java
@@ -226,7 +226,11 @@ public class DrawBitmapFontText extends PaintOperation implements VariableSuppor
xPos += glyph.mMarginLeft;
float xPos2 = xPos + glyph.mBitmapWidth;
context.drawBitmap(
- glyph.mBitmapId, xPos, mY + glyph.mMarginTop, xPos2, mY + glyph.mBitmapHeight);
+ glyph.mBitmapId,
+ xPos,
+ mY + glyph.mMarginTop,
+ xPos2,
+ mY + glyph.mBitmapHeight + glyph.mMarginTop);
xPos = xPos2 + glyph.mMarginRight;
}
}
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 0901ae3eca75..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;
@@ -153,33 +154,44 @@ public class FloatExpression extends Operation implements VariableSupport, Seria
if (Float.isNaN(mLastChange)) {
mLastChange = t;
}
- if (mFloatAnimation != null && !Float.isNaN(mLastCalculatedValue)) {
+ if (mFloatAnimation != null) { // support animations
+ if (Float.isNaN(mLastCalculatedValue)) { // startup
+ try {
+ mLastCalculatedValue =
+ mExp.eval(
+ context.getCollectionsAccess(),
+ mPreCalcValue,
+ mPreCalcValue.length);
+ mFloatAnimation.setTargetValue(mLastCalculatedValue);
+ if (Float.isNaN(mFloatAnimation.getInitialValue())) {
+ mFloatAnimation.setInitialValue(mLastCalculatedValue);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(
+ this.toString() + " len = " + mPreCalcValue.length, e);
+ }
+ }
float lastComputedValue = mFloatAnimation.get(t - mLastChange);
if (lastComputedValue != mLastAnimatedValue) {
mLastAnimatedValue = lastComputedValue;
context.loadFloat(mId, lastComputedValue);
context.needsRepaint();
- if (mFloatAnimation.isPropagate()) {
- markDirty();
- }
+ markDirty();
}
- } else if (mSpring != null) {
+ } else if (mSpring != null) { // support damped spring animation
float lastComputedValue = mSpring.get(t - mLastChange);
if (lastComputedValue != mLastAnimatedValue) {
mLastAnimatedValue = lastComputedValue;
context.loadFloat(mId, lastComputedValue);
context.needsRepaint();
}
- } else {
+ } else { // no animation
float v = 0;
try {
v = mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
} catch (Exception e) {
throw new RuntimeException(this.toString() + " len = " + mPreCalcValue.length, e);
}
- if (mFloatAnimation != null) {
- mFloatAnimation.setTargetValue(v);
- }
context.loadFloat(mId, v);
}
}
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/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index e5914eb7fd28..9a06ef165c3b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -73,6 +73,11 @@ public class LoopOperation extends PaintOperation
mUntilOut = Float.isNaN(mUntil) ? context.getFloat(Utils.idFromNan(mUntil)) : mUntil;
mFromOut = Float.isNaN(mFrom) ? context.getFloat(Utils.idFromNan(mFrom)) : mFrom;
mStepOut = Float.isNaN(mStep) ? context.getFloat(Utils.idFromNan(mStep)) : mStep;
+ for (Operation op : mList) {
+ if (op instanceof VariableSupport && op.isDirty()) {
+ ((VariableSupport) op).updateVariables(context);
+ }
+ }
}
public LoopOperation(int indexId, float from, float step, float until) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
index 6ee18bbbd7e0..73caa1b997ee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
@@ -120,10 +120,6 @@ public class BoxLayout extends LayoutManager {
size.setHeight(Math.max(size.getHeight(), m.getH()));
}
}
- // add padding
- size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext())));
- size.setHeight(
- Math.max(size.getHeight(), computeModifierDefinedHeight(context.getContext())));
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java
index ff7a3af11f20..fa16c12ecd2f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/FitBoxLayout.java
@@ -156,11 +156,6 @@ public class FitBoxLayout extends LayoutManager {
} else {
self.setVisibility(Visibility.VISIBLE);
}
-
- // add padding
- size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext())));
- size.setHeight(
- Math.max(size.getHeight(), computeModifierDefinedHeight(context.getContext())));
}
@Override
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 eb10ead34781..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 {
@@ -133,9 +135,7 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
return mHeightModifier.isFill();
}
- /** Base implementation of the measure resolution */
- @Override
- public void measure(
+ private void measure_v0_4_0(
@NonNull PaintContext context,
float minWidth,
float maxWidth,
@@ -279,6 +279,182 @@ public abstract class LayoutManager extends LayoutComponent implements Measurabl
internalLayoutMeasure(context, measure);
}
+ private void measure_v0_4_1(
+ @NonNull PaintContext context,
+ float minWidth,
+ float maxWidth,
+ float minHeight,
+ float maxHeight,
+ @NonNull MeasurePass measure) {
+
+ float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth(context.getContext()));
+ float measuredHeight =
+ Math.min(maxHeight, computeModifierDefinedHeight(context.getContext()));
+
+ 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;
+
+ boolean hasHorizontalWrap = false;
+ boolean hasVerticalWrap = false;
+
+ if (isInHorizontalFill()) {
+ measuredWidth = maxWidth;
+ } else if (mWidthModifier.hasWeight()) {
+ measuredWidth =
+ Math.max(measuredWidth, computeModifierDefinedWidth(context.getContext()));
+ } else {
+ measuredWidth = Math.max(measuredWidth, minWidth);
+ measuredWidth = Math.min(measuredWidth, maxWidth);
+ hasHorizontalWrap = mWidthModifier.isWrap() || mWidthModifier.isIntrinsicMin();
+ }
+
+ if (isInVerticalFill()) {
+ measuredHeight = maxHeight;
+ } else if (mHeightModifier.hasWeight()) {
+ measuredHeight =
+ Math.max(measuredHeight, computeModifierDefinedHeight(context.getContext()));
+ } else {
+ measuredHeight = Math.max(measuredHeight, minHeight);
+ measuredHeight = Math.min(measuredHeight, maxHeight);
+ hasVerticalWrap = mHeightModifier.isWrap() || mHeightModifier.isIntrinsicMin();
+ }
+
+ if (minWidth == maxWidth) {
+ measuredWidth = maxWidth;
+ }
+ if (minHeight == maxHeight) {
+ measuredHeight = maxHeight;
+ }
+
+ if (hasHorizontalWrap || hasVerticalWrap) {
+ mCachedWrapSize.setWidth(0f);
+ mCachedWrapSize.setHeight(0f);
+ computeWrapSize(
+ context,
+ insetMaxWidth,
+ insetMaxHeight,
+ mWidthModifier.isWrap(),
+ mHeightModifier.isWrap(),
+ measure,
+ mCachedWrapSize);
+ int selfVisibilityAfterMeasure = measure.get(this).getVisibility();
+ if (Visibility.hasOverride(selfVisibilityAfterMeasure)
+ && mScheduledVisibility != selfVisibilityAfterMeasure) {
+ mScheduledVisibility = selfVisibilityAfterMeasure;
+ }
+ 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()) {
+ mCachedWrapSize.setWidth(0f);
+ mCachedWrapSize.setHeight(0f);
+ computeWrapSize(
+ context,
+ Float.MAX_VALUE,
+ maxHeight,
+ false,
+ false,
+ measure,
+ mCachedWrapSize);
+ float w = mCachedWrapSize.getWidth();
+ if (hasHorizontalScroll()) {
+ computeSize(context, 0f, w, 0, measuredHeight, measure);
+ mComponentModifiers.setHorizontalScrollDimension(measuredWidth, w);
+ } else {
+ computeSize(
+ context,
+ 0f,
+ Math.min(measuredWidth, insetMaxWidth),
+ 0f,
+ Math.min(measuredHeight, insetMaxHeight),
+ measure);
+ }
+ } else if (hasVerticalIntrinsicDimension()) {
+ mCachedWrapSize.setWidth(0f);
+ mCachedWrapSize.setHeight(0f);
+ computeWrapSize(
+ context, maxWidth, Float.MAX_VALUE, false, false, measure, mCachedWrapSize);
+ float h = mCachedWrapSize.getHeight();
+ if (hasVerticalScroll()) {
+ computeSize(context, 0f, measuredWidth, 0, h, measure);
+ mComponentModifiers.setVerticalScrollDimension(measuredHeight, h);
+ } else {
+ computeSize(
+ context,
+ 0f,
+ Math.min(measuredWidth, insetMaxWidth),
+ 0f,
+ Math.min(measuredHeight, insetMaxHeight),
+ measure);
+ }
+ } else {
+ float maxChildWidth = measuredWidth - mPaddingLeft - mPaddingRight;
+ float maxChildHeight = measuredHeight - mPaddingTop - mPaddingBottom;
+ computeSize(context, 0, maxChildWidth, 0, maxChildHeight, measure);
+ }
+ }
+
+ if (mContent != null) {
+ ComponentMeasure cm = measure.get(mContent);
+ cm.setX(0f);
+ cm.setY(0f);
+ cm.setW(measuredWidth);
+ cm.setH(measuredHeight);
+ }
+
+ measuredWidth = Math.max(measuredWidth, minWidth);
+ measuredHeight = Math.max(measuredHeight, minHeight);
+
+ ComponentMeasure m = measure.get(this);
+ m.setW(measuredWidth);
+ m.setH(measuredHeight);
+ m.setVisibility(mScheduledVisibility);
+
+ internalLayoutMeasure(context, measure);
+ }
+
+ /** Base implementation of the measure resolution */
+ @Override
+ public void measure(
+ @NonNull PaintContext context,
+ float minWidth,
+ float maxWidth,
+ float minHeight,
+ float maxHeight,
+ @NonNull MeasurePass measure) {
+
+ if (context.supportsVersion(0, 4, 1)) {
+ measure_v0_4_1(context, minWidth, maxWidth, minHeight, maxHeight, measure);
+ } else {
+ measure_v0_4_0(context, minWidth, maxWidth, minHeight, maxHeight, measure);
+ }
+ }
+
private boolean hasHorizontalScroll() {
return mComponentModifiers.hasHorizontalScroll();
}
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 120c740eccda..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;
@@ -226,7 +236,7 @@ public class TextLayout extends LayoutManager implements VariableSupport, Access
break;
case TEXT_ALIGN_RIGHT:
case TEXT_ALIGN_END:
- px = (mWidth - mPaddingRight - mTextW);
+ px = (mWidth - mPaddingLeft - mPaddingRight - mTextW);
break;
case TEXT_ALIGN_LEFT:
case TEXT_ALIGN_START:
@@ -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/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 55b64364e4e5..9c6f0a47b1c1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -1411,7 +1411,7 @@ public class PaintBundle implements Serializable {
list.add(
orderedOf(
"type",
- "LinearGradient",
+ "RadialGradient",
"colors",
colors,
"stops",
@@ -1431,7 +1431,7 @@ public class PaintBundle implements Serializable {
list.add(
orderedOf(
"type",
- "LinearGradient",
+ "SweepGradient",
"colors",
colors,
"stops",
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
index 349ab6117b2b..03fafaee631e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -437,8 +437,8 @@ public class FloatAnimation extends Easing implements Serializable {
serializer
.addType("FloatAnimation")
.add("initialValue", mInitialValue)
- .add("targetValue", mInitialValue)
- .add("duration", mInitialValue)
+ .add("targetValue", mTargetValue)
+ .add("duration", mDuration)
.add("easing", Easing.getString(mEasingCurve.getType()));
}
}
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 f5b2cca15e43..510e4c4cc2c6 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -21,6 +21,7 @@ import static com.android.internal.widget.remotecompose.core.CoreDocument.MINOR_
import android.app.Application;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -136,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);
@@ -149,6 +154,7 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
RemoteComposeTouchHelper.REGISTRAR.clearAccessibilityDelegate(this);
}
+
mapColors();
setupSensors();
mInner.setHapticEngine(
@@ -263,6 +269,45 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
}
/**
+ * Set an override for a user domain int resource
+ *
+ * @param name name of the int
+ * @param value value of the int
+ */
+ public void setUserLocalColor(String name, int value) {
+ mInner.setLocalColor("USER:" + name, value);
+ }
+
+ /**
+ * Set an override for a user domain float resource
+ *
+ * @param name name of the float
+ * @param value value of the float
+ */
+ public void setUserLocalFloat(String name, float value) {
+ mInner.setLocalFloat("USER:" + name, value);
+ }
+
+ /**
+ * Set an override for a user domain int resource
+ *
+ * @param name name of the int
+ * @param value value of the int
+ */
+ public void setUserLocalBitmap(String name, Bitmap value) {
+ mInner.setLocalBitmap("USER:" + name, value);
+ }
+
+ /**
+ * Clear the override of the given user bitmap
+ *
+ * @param name name of the bitmap
+ */
+ public void clearUserLocalBitmap(String name) {
+ mInner.clearLocalBitmap("USER:" + name);
+ }
+
+ /**
* Clear the override of the given user string
*
* @param name name of the string
@@ -281,6 +326,24 @@ public class RemoteComposePlayer extends FrameLayout implements RemoteContextAwa
}
/**
+ * Clear the override of the given user color
+ *
+ * @param name name of the color
+ */
+ public void clearUserLocalColor(String name) {
+ mInner.clearLocalColor("USER:" + name);
+ }
+
+ /**
+ * Clear the override of the given user int
+ *
+ * @param name name of the int
+ */
+ public void clearUserLocalFloat(String name) {
+ mInner.clearLocalFloat("USER:" + name);
+ }
+
+ /**
* Set an override for a system domain string resource
*
* @param name name of the string
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 680a221cc2db..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;
}
@@ -276,8 +379,7 @@ public class AndroidPaintContext extends PaintContext {
}
mPaint.getFontMetrics(mCachedFontMetrics);
mPaint.getTextBounds(str, start, end, mTmpRect);
- if ((flags & PaintContext.TEXT_MEASURE_SPACES) != 0
- && (str.startsWith(" ") || str.endsWith(" "))) {
+ if ((flags & PaintContext.TEXT_MEASURE_SPACES) != 0) {
bounds[0] = 0f;
bounds[2] = mPaint.measureText(str, start, end);
} else {
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 e76fb0654df6..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) {
@@ -253,6 +256,31 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta
}
}
+ /**
+ * Set a local named color
+ *
+ * @param name
+ * @param content
+ */
+ public void setLocalColor(String name, int content) {
+ mARContext.setNamedColorOverride(name, content);
+ if (mDocument != null) {
+ mDocument.invalidate();
+ }
+ }
+
+ /**
+ * Clear a local named color
+ *
+ * @param name
+ */
+ public void clearLocalColor(String name) {
+ mARContext.clearNamedDataOverride(name);
+ if (mDocument != null) {
+ mDocument.invalidate();
+ }
+ }
+
public void setLocalFloat(String name, Float content) {
mARContext.setNamedFloatOverride(name, content);
if (mDocument != null) {
@@ -619,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();
+ }
}