Loading core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +113 −73 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.internal.widget.remotecompose.core.serialize.Serializable; import com.android.internal.widget.remotecompose.core.types.IntegerConstant; import com.android.internal.widget.remotecompose.core.types.LongConstant; import java.time.Clock; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; Loading @@ -65,11 +66,11 @@ public class CoreDocument implements Serializable { // Semantic version public static final int MAJOR_VERSION = 1; public static final int MINOR_VERSION = 0; public static final int MINOR_VERSION = 1; public static final int PATCH_VERSION = 0; // Internal version level public static final int DOCUMENT_API_LEVEL = 6; public static final int DOCUMENT_API_LEVEL = 7; // We also keep a more fine-grained BUILD number, exposed as // ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD Loading @@ -87,8 +88,8 @@ public class CoreDocument implements Serializable { // Semantic version of the document @NonNull Version mVersion = new Version(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION); @Nullable String mContentDescription; // text description of the document (used for accessibility) @Nullable String mContentDescription; // text description of the document (used for accessibility) long mRequiredCapabilities = 0L; // bitmask indicating needed capabilities of the player(unused) int mWidth = 0; // horizontal dimension of the document in pixels Loading @@ -100,20 +101,36 @@ public class CoreDocument implements Serializable { int mContentAlignment = RootContentBehavior.ALIGNMENT_CENTER; @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState); @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(); private final HashMap<Long, IntegerExpression> mIntegerExpressions = new HashMap<>(); private final HashMap<Integer, FloatExpression> mFloatExpressions = new HashMap<>(); private HashSet<Component> mAppliedTouchOperations = new HashSet<>(); private final @NonNull Clock mClock; private final HashSet<Component> mAppliedTouchOperations = new HashSet<>(); private int mLastId = 1; // last component id when inflating the file private IntMap<Object> mDocProperties; private @Nullable IntMap<Object> mDocProperties; boolean mFirstPaint = true; private boolean mIsUpdateDoc = false; private int mHostExceptionID = 0; public CoreDocument() { this(new SystemClock()); } public CoreDocument(@NonNull Clock clock) { this.mClock = clock; mTimeVariables = new TimeVariables(clock); } public @NonNull Clock getClock() { return mClock; } /** Returns a version number that is monotonically increasing. */ public static int getDocumentApiLevel() { Loading Loading @@ -333,7 +350,7 @@ public class CoreDocument implements Serializable { /** * Returns the list of click areas * * @return list of click areas in document coordinates * @return set of click areas in document coordinates */ @NonNull public Set<ClickAreaRepresentation> getClickAreas() { Loading Loading @@ -422,7 +439,7 @@ public class CoreDocument implements Serializable { } @Override public void serialize(MapSerializer serializer) { public void serialize(@NonNull MapSerializer serializer) { serializer .addType("CoreDocument") .add("width", mWidth) Loading @@ -435,7 +452,7 @@ public class CoreDocument implements Serializable { * * @param properties the properties to set */ public void setProperties(IntMap<Object> properties) { public void setProperties(@Nullable IntMap<Object> properties) { mDocProperties = properties; } Loading @@ -443,7 +460,7 @@ public class CoreDocument implements Serializable { * @param key the key * @return the value associated with the key */ public Object getProperty(short key) { public @Nullable Object getProperty(short key) { if (mDocProperties == null) { return null; } Loading @@ -455,7 +472,7 @@ public class CoreDocument implements Serializable { * * @param delta the delta to apply */ public void applyUpdate(CoreDocument delta) { public void applyUpdate(@NonNull CoreDocument delta) { HashMap<Integer, TextData> txtData = new HashMap<Integer, TextData>(); HashMap<Integer, BitmapData> imgData = new HashMap<Integer, BitmapData>(); HashMap<Integer, FloatConstant> fltData = new HashMap<Integer, FloatConstant>(); Loading Loading @@ -535,6 +552,24 @@ public class CoreDocument implements Serializable { }); } /** * Set the host Action id to call if an exception occurs * * @param exceptionID host action id */ public void setHostExceptionID(int exceptionID) { mHostExceptionID = exceptionID; } /** * Get the host Action id to call if an exception occurs * * @return the host Action id to call if an exception occurs */ public int getHostExceptionID() { return mHostExceptionID; } private interface Visitor { void visit(Operation op); } Loading @@ -558,9 +593,9 @@ public class CoreDocument implements Serializable { void haptic(int type); } HapticEngine mHapticEngine; @Nullable HapticEngine mHapticEngine; public void setHapticEngine(HapticEngine engine) { public void setHapticEngine(@NonNull HapticEngine engine) { mHapticEngine = engine; } Loading @@ -582,7 +617,7 @@ public class CoreDocument implements Serializable { * * @param component the component applying the touch */ public void appliedTouchOperation(Component component) { public void appliedTouchOperation(@NonNull Component component) { mAppliedTouchOperations.add(component); } Loading @@ -594,7 +629,7 @@ public class CoreDocument implements Serializable { * @param name the action name * @param value the payload of the action */ void onAction(@NonNull String name, Object value); void onAction(@NonNull String name, @Nullable Object value); } @NonNull HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>(); Loading @@ -605,7 +640,7 @@ public class CoreDocument implements Serializable { * @param name the action name * @param value a parameter to the action */ public void runNamedAction(@NonNull String name, Object value) { public void runNamedAction(@NonNull String name, @Nullable Object value) { // TODO: we might add an interface to group all valid parameter types for (ActionCallback callback : mActionListeners) { callback.onAction(name, value); Loading @@ -615,7 +650,7 @@ public class CoreDocument implements Serializable { /** * Add a callback for handling the named host actions * * @param callback * @param callback action callback */ public void addActionCallback(@NonNull ActionCallback callback) { mActionListeners.add(callback); Loading Loading @@ -877,13 +912,14 @@ public class CoreDocument implements Serializable { return ops; } @NonNull private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); @NonNull private final HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); /** * Register all the operations recursively * * @param context * @param list * @param context the context * @param list list of operations */ private void registerVariables( @NonNull RemoteContext context, @NonNull ArrayList<Operation> list) { Loading Loading @@ -920,8 +956,8 @@ public class CoreDocument implements Serializable { /** * Apply the operations recursively, for the original initialization pass with mode == DATA * * @param context * @param list * @param context the context * @param list list of operations */ private void applyOperations( @NonNull RemoteContext context, @NonNull ArrayList<Operation> list) { Loading Loading @@ -1030,16 +1066,16 @@ public class CoreDocument implements Serializable { new ClickAreaRepresentation( id, contentDescription, left, top, right, bottom, metadata); boolean old = mClickAreas.remove(car); mClickAreas.remove(car); mClickAreas.add(car); } /** * Called by commands to listen to touch events * * @param listener * @param listener touch listener */ public void addTouchListener(TouchListener listener) { public void addTouchListener(@NonNull TouchListener listener) { mTouchListeners.add(listener); } Loading Loading @@ -1090,9 +1126,7 @@ public class CoreDocument implements Serializable { } } for (IdActionCallback listener : mIdActionListeners) { listener.onAction(id, metadata); } notifyOfException(id, metadata); Component component = getComponent(id); if (component != null) { Loading @@ -1100,13 +1134,23 @@ public class CoreDocument implements Serializable { } } /** Warn click listeners when a click area is activated */ private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { /** * trigger host Actions on exception. Exception handler should be registered in header * * @param id id of the exception * @param metadata the exception string */ public void notifyOfException(int id, @Nullable String metadata) { for (IdActionCallback listener : mIdActionListeners) { listener.onAction(clickArea.mId, clickArea.mMetadata); listener.onAction(id, metadata); } } /** Warn click listeners when a click area is activated */ private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { notifyOfException(clickArea.mId, clickArea.mMetadata); } /** * Returns true if the document has touch listeners * Loading @@ -1114,7 +1158,7 @@ public class CoreDocument implements Serializable { */ public boolean hasTouchListener() { boolean hasComponentsTouchListeners = mRootLayoutComponent != null && mRootLayoutComponent.hasTouchListeners(); mRootLayoutComponent != null && mRootLayoutComponent.getHasTouchListeners(); return hasComponentsTouchListeners || !mTouchListeners.isEmpty(); } Loading @@ -1125,7 +1169,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public boolean touchDrag(RemoteContext context, float x, float y) { public boolean touchDrag(@NonNull RemoteContext context, float x, float y) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1139,10 +1183,7 @@ public class CoreDocument implements Serializable { return true; } } if (!mTouchListeners.isEmpty()) { return true; } return false; return !mTouchListeners.isEmpty(); } /** Loading @@ -1151,7 +1192,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchDown(RemoteContext context, float x, float y) { public void touchDown(@NonNull RemoteContext context, float x, float y) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1169,7 +1210,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { public void touchUp(@NonNull RemoteContext context, float x, float y, float dx, float dy) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1190,7 +1231,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchCancel(RemoteContext context, float x, float y, float dx, float dy) { public void touchCancel(@NonNull RemoteContext context, float x, float y, float dx, float dy) { if (mRootLayoutComponent != null) { for (Component component : mAppliedTouchOperations) { component.onTouchCancel(context, this, x, y, true); Loading Loading @@ -1226,7 +1267,7 @@ public class CoreDocument implements Serializable { * * @return array of named variables or null */ public String[] getNamedVariables(int type) { public @NonNull String [] getNamedVariables(int type) { ArrayList<String> ret = new ArrayList<>(); getNamedVars(type, mOperations, ret); return ret.toArray(new String[0]); Loading Loading @@ -1267,7 +1308,7 @@ public class CoreDocument implements Serializable { /** * Returns > 0 if it needs to repaint * * @return * @return 0 if needs to repaint */ public int needsRepaint() { return mRepaintNext; Loading @@ -1277,8 +1318,8 @@ public class CoreDocument implements Serializable { * Traverse the list of operations to update the variables. TODO: this should walk the * dependency tree instead * * @param context * @param operations * @param context the context * @param operations list of operations */ private void updateVariables( @NonNull RemoteContext context, int theme, List<Operation> operations) { Loading @@ -1303,6 +1344,7 @@ public class CoreDocument implements Serializable { */ public void paint(@NonNull RemoteContext context, int theme) { context.clearLastOpCount(); assert context.getPaintContext() != null; context.getPaintContext().clearNeedsRepaint(); context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity()); context.mMode = RemoteContext.ContextMode.UNSET; Loading Loading @@ -1331,8 +1373,8 @@ public class CoreDocument implements Serializable { float sw = mScaleOutput[0]; float sh = mScaleOutput[1]; computeTranslate(context.mWidth, context.mHeight, sw, sh, mTranslateOutput); context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]); context.mPaintContext.scale(sw, sh); context.getPaintContext().translate(mTranslateOutput[0], mTranslateOutput[1]); context.getPaintContext().scale(sw, sh); } else { // If not, we set the document width and height to be the current context width and // height. Loading Loading @@ -1407,23 +1449,22 @@ public class CoreDocument implements Serializable { int count = mOperations.size(); for (Operation mOperation : mOperations) { if (mOperation instanceof Component) { count += getChildOps((Component) mOperation); if (mOperation instanceof Container) { count += getChildOps((Container) mOperation); } } return count; } private int getChildOps(@NonNull Component base) { int count = base.mList.size(); for (Operation mOperation : base.mList) { if (mOperation instanceof Component) { private int getChildOps(@NonNull Container base) { int count = base.getList().size(); for (Operation operation : base.getList()) { if (operation instanceof Container) { int mult = 1; if (mOperation instanceof LoopOperation) { mult = ((LoopOperation) mOperation).estimateIterations(); if (operation instanceof LoopOperation) { mult = ((LoopOperation) operation).estimateIterations(); } count += mult * getChildOps((Component) mOperation); count += mult * getChildOps((Container) operation); } } return count; Loading @@ -1432,7 +1473,7 @@ public class CoreDocument implements Serializable { /** * Returns a list of useful statistics for the runtime document * * @return * @return array of strings representing some useful statistics */ @NonNull public String[] getStats() { Loading @@ -1440,8 +1481,8 @@ public class CoreDocument implements Serializable { WireBuffer buffer = new WireBuffer(); int count = mOperations.size(); HashMap<String, int[]> map = new HashMap<>(); for (Operation mOperation : mOperations) { Class<? extends Operation> c = mOperation.getClass(); for (Operation operation : mOperations) { Class<? extends Operation> c = operation.getClass(); int[] values; if (map.containsKey(c.getSimpleName())) { values = map.get(c.getSimpleName()); Loading @@ -1451,12 +1492,9 @@ public class CoreDocument implements Serializable { } values[0] += 1; values[1] += sizeOfComponent(mOperation, buffer); if (mOperation instanceof Container) { Container com = (Container) mOperation; count += addChildren(com, map, buffer); } else if (mOperation instanceof LoopOperation) { LoopOperation com = (LoopOperation) mOperation; values[1] += sizeOfComponent(operation, buffer); if (operation instanceof Container) { Container com = (Container) operation; count += addChildren(com, map, buffer); } } Loading Loading @@ -1503,7 +1541,7 @@ public class CoreDocument implements Serializable { * Returns a string representation of the operations, traversing the list of operations & * containers * * @return * @return representation of operations */ @NonNull public String toNestedString() { Loading Loading @@ -1545,7 +1583,7 @@ public class CoreDocument implements Serializable { * @param shader the source of the shader * @return true if the shader is allowed to run */ boolean isShaderValid(String shader); boolean isShaderValid(@NonNull String shader); } /** Loading @@ -1554,7 +1592,7 @@ public class CoreDocument implements Serializable { * @param context the remote context * @param ctl the call back to allow evaluation of shaders */ public void checkShaders(RemoteContext context, ShaderControl ctl) { public void checkShaders(@NonNull RemoteContext context, @NonNull ShaderControl ctl) { checkShaders(context, ctl, mOperations); } Loading @@ -1578,15 +1616,17 @@ public class CoreDocument implements Serializable { ShaderData sd = (ShaderData) op; int id = sd.getShaderTextId(); String str = context.getText(id); if (str != null) { sd.enable(ctl.isShaderValid(str)); } } } } /** * Set if this is an update doc * * @param isUpdateDoc * @param isUpdateDoc true if the doc represents update operations rather than a normal doc */ public void setUpdateDoc(boolean isUpdateDoc) { mIsUpdateDoc = isUpdateDoc; Loading core/java/com/android/internal/widget/remotecompose/core/MatrixAccess.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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; import android.annotation.NonNull; import android.annotation.Nullable; import java.text.DecimalFormat; /** Support access to floats in matrix */ public interface MatrixAccess { /** * Get a the matrix * * @return the matrix */ @NonNull float [] get(); /** * Convert a 4x4 matrix to a 3x3 matrix * * @param matrix 4x4 matrix * @return 3x3 matrix */ static @Nullable float [] to3x3(@NonNull float [] matrix) { if (matrix.length == 16) { float[] matrix3x3 = new float[9]; float[] matrix4x4; matrix4x4 = matrix; matrix3x3[0] = matrix4x4[0]; matrix3x3[1] = matrix4x4[1]; matrix3x3[2] = matrix4x4[3]; // Column 1 matrix3x3[3] = matrix4x4[4]; matrix3x3[4] = matrix4x4[5]; matrix3x3[5] = matrix4x4[7]; // Column 2 matrix3x3[6] = matrix4x4[8]; matrix3x3[7] = matrix4x4[9]; matrix3x3[8] = matrix4x4[15]; // should be 1. Not sure about this return matrix3x3; } else if (matrix.length == 9) { return matrix; } return null; } /** * Dump a matrix to the console * * @param m matrix */ static void dump(@NonNull float [] m) { String str = ""; int step = m.length == 16 ? 4 : 3; DecimalFormat df = new DecimalFormat("0.00"); for (int i = 0; i < m.length; i++) { if (i % step == 0) { str += "\n"; } str += df.format(m[i]) + " "; } System.out.println(str); } } core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java +1 −2 Original line number Diff line number Diff line Loading @@ -31,8 +31,7 @@ public interface OperationInterface { void apply(@NonNull RemoteContext context); /** Debug utility to display an operation + indentation */ @NonNull String deepToString(@NonNull String indent); @NonNull String deepToString(@NonNull String indent); /** * Returns true if the operation is marked as "dirty" Loading core/java/com/android/internal/widget/remotecompose/core/Operations.java +277 −6 File changed.Preview size limit exceeded, changes collapsed. Show changes core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +31 −7 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import java.time.Clock; import java.util.HashMap; /** Specify an abstract paint context used by RemoteCompose commands to draw */ Loading Loading @@ -75,6 +76,10 @@ public abstract class PaintContext { matrixSave(); } public @NonNull Clock getClock() { return mContext.getClock(); } /** * Draw a bitmap * Loading Loading @@ -213,7 +218,7 @@ public abstract class PaintContext { * * @param paint */ public abstract void replacePaint(PaintBundle paint); public abstract void replacePaint(@NonNull PaintBundle paint); /** * draw a round rect Loading Loading @@ -280,7 +285,7 @@ public abstract class PaintContext { * * @return an instance of a ComputedTextLayout (typically if complex text drawing is used) */ public abstract Platform.ComputedTextLayout layoutComplexText( public abstract @Nullable Platform.ComputedTextLayout layoutComplexText( int textId, int start, int end, Loading Loading @@ -317,7 +322,7 @@ public abstract class PaintContext { * * @param computedTextLayout pre-computed text layout */ public abstract void drawComplexText(Platform.ComputedTextLayout computedTextLayout); public abstract void drawComplexText(@Nullable Platform.ComputedTextLayout computedTextLayout); /** * Draw an interpolation between two paths Loading Loading @@ -446,7 +451,7 @@ public abstract class PaintContext { * @return true if in debug mode, false otherwise */ public boolean isDebug() { return mContext.isDebug(); return mContext.isBasicDebug(); } /** Loading Loading @@ -497,10 +502,10 @@ public abstract class PaintContext { /** * Returns a String from an id * * @param textID * @param textId * @return the string if found */ public abstract @Nullable String getText(int textID); public abstract @Nullable String getText(int textId); /** * Returns true if the document has been encoded for at least the given version MAJOR.MINOR Loading @@ -513,4 +518,23 @@ public abstract class PaintContext { public boolean supportsVersion(int major, int minor, int patch) { return mContext.supportsVersion(major, minor, patch); } /** * Sets the Matrix from the path * * @param pathId id of the path * @param fraction fractional position in the path to use * @param vOffset vertical offset * @param flags flags */ public abstract void matrixFromPath(int pathId, float fraction, float vOffset, int flags); /** * Redirect drawing to a bitmap (0 = back to main canvas) * * @param bitmapId id of bitmap to draw to or 0 to draw to the canvas * @param mode flags support init of bitmap 0 = clear to color, 1 = no clear * @param color set the initial color of the bitmap */ public abstract void drawToBitmap(int bitmapId, int mode, int color); } Loading
core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +113 −73 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import com.android.internal.widget.remotecompose.core.serialize.Serializable; import com.android.internal.widget.remotecompose.core.types.IntegerConstant; import com.android.internal.widget.remotecompose.core.types.LongConstant; import java.time.Clock; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; Loading @@ -65,11 +66,11 @@ public class CoreDocument implements Serializable { // Semantic version public static final int MAJOR_VERSION = 1; public static final int MINOR_VERSION = 0; public static final int MINOR_VERSION = 1; public static final int PATCH_VERSION = 0; // Internal version level public static final int DOCUMENT_API_LEVEL = 6; public static final int DOCUMENT_API_LEVEL = 7; // We also keep a more fine-grained BUILD number, exposed as // ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD Loading @@ -87,8 +88,8 @@ public class CoreDocument implements Serializable { // Semantic version of the document @NonNull Version mVersion = new Version(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION); @Nullable String mContentDescription; // text description of the document (used for accessibility) @Nullable String mContentDescription; // text description of the document (used for accessibility) long mRequiredCapabilities = 0L; // bitmask indicating needed capabilities of the player(unused) int mWidth = 0; // horizontal dimension of the document in pixels Loading @@ -100,20 +101,36 @@ public class CoreDocument implements Serializable { int mContentAlignment = RootContentBehavior.ALIGNMENT_CENTER; @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState); @NonNull RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(); private final HashMap<Long, IntegerExpression> mIntegerExpressions = new HashMap<>(); private final HashMap<Integer, FloatExpression> mFloatExpressions = new HashMap<>(); private HashSet<Component> mAppliedTouchOperations = new HashSet<>(); private final @NonNull Clock mClock; private final HashSet<Component> mAppliedTouchOperations = new HashSet<>(); private int mLastId = 1; // last component id when inflating the file private IntMap<Object> mDocProperties; private @Nullable IntMap<Object> mDocProperties; boolean mFirstPaint = true; private boolean mIsUpdateDoc = false; private int mHostExceptionID = 0; public CoreDocument() { this(new SystemClock()); } public CoreDocument(@NonNull Clock clock) { this.mClock = clock; mTimeVariables = new TimeVariables(clock); } public @NonNull Clock getClock() { return mClock; } /** Returns a version number that is monotonically increasing. */ public static int getDocumentApiLevel() { Loading Loading @@ -333,7 +350,7 @@ public class CoreDocument implements Serializable { /** * Returns the list of click areas * * @return list of click areas in document coordinates * @return set of click areas in document coordinates */ @NonNull public Set<ClickAreaRepresentation> getClickAreas() { Loading Loading @@ -422,7 +439,7 @@ public class CoreDocument implements Serializable { } @Override public void serialize(MapSerializer serializer) { public void serialize(@NonNull MapSerializer serializer) { serializer .addType("CoreDocument") .add("width", mWidth) Loading @@ -435,7 +452,7 @@ public class CoreDocument implements Serializable { * * @param properties the properties to set */ public void setProperties(IntMap<Object> properties) { public void setProperties(@Nullable IntMap<Object> properties) { mDocProperties = properties; } Loading @@ -443,7 +460,7 @@ public class CoreDocument implements Serializable { * @param key the key * @return the value associated with the key */ public Object getProperty(short key) { public @Nullable Object getProperty(short key) { if (mDocProperties == null) { return null; } Loading @@ -455,7 +472,7 @@ public class CoreDocument implements Serializable { * * @param delta the delta to apply */ public void applyUpdate(CoreDocument delta) { public void applyUpdate(@NonNull CoreDocument delta) { HashMap<Integer, TextData> txtData = new HashMap<Integer, TextData>(); HashMap<Integer, BitmapData> imgData = new HashMap<Integer, BitmapData>(); HashMap<Integer, FloatConstant> fltData = new HashMap<Integer, FloatConstant>(); Loading Loading @@ -535,6 +552,24 @@ public class CoreDocument implements Serializable { }); } /** * Set the host Action id to call if an exception occurs * * @param exceptionID host action id */ public void setHostExceptionID(int exceptionID) { mHostExceptionID = exceptionID; } /** * Get the host Action id to call if an exception occurs * * @return the host Action id to call if an exception occurs */ public int getHostExceptionID() { return mHostExceptionID; } private interface Visitor { void visit(Operation op); } Loading @@ -558,9 +593,9 @@ public class CoreDocument implements Serializable { void haptic(int type); } HapticEngine mHapticEngine; @Nullable HapticEngine mHapticEngine; public void setHapticEngine(HapticEngine engine) { public void setHapticEngine(@NonNull HapticEngine engine) { mHapticEngine = engine; } Loading @@ -582,7 +617,7 @@ public class CoreDocument implements Serializable { * * @param component the component applying the touch */ public void appliedTouchOperation(Component component) { public void appliedTouchOperation(@NonNull Component component) { mAppliedTouchOperations.add(component); } Loading @@ -594,7 +629,7 @@ public class CoreDocument implements Serializable { * @param name the action name * @param value the payload of the action */ void onAction(@NonNull String name, Object value); void onAction(@NonNull String name, @Nullable Object value); } @NonNull HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>(); Loading @@ -605,7 +640,7 @@ public class CoreDocument implements Serializable { * @param name the action name * @param value a parameter to the action */ public void runNamedAction(@NonNull String name, Object value) { public void runNamedAction(@NonNull String name, @Nullable Object value) { // TODO: we might add an interface to group all valid parameter types for (ActionCallback callback : mActionListeners) { callback.onAction(name, value); Loading @@ -615,7 +650,7 @@ public class CoreDocument implements Serializable { /** * Add a callback for handling the named host actions * * @param callback * @param callback action callback */ public void addActionCallback(@NonNull ActionCallback callback) { mActionListeners.add(callback); Loading Loading @@ -877,13 +912,14 @@ public class CoreDocument implements Serializable { return ops; } @NonNull private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); @NonNull private final HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>(); /** * Register all the operations recursively * * @param context * @param list * @param context the context * @param list list of operations */ private void registerVariables( @NonNull RemoteContext context, @NonNull ArrayList<Operation> list) { Loading Loading @@ -920,8 +956,8 @@ public class CoreDocument implements Serializable { /** * Apply the operations recursively, for the original initialization pass with mode == DATA * * @param context * @param list * @param context the context * @param list list of operations */ private void applyOperations( @NonNull RemoteContext context, @NonNull ArrayList<Operation> list) { Loading Loading @@ -1030,16 +1066,16 @@ public class CoreDocument implements Serializable { new ClickAreaRepresentation( id, contentDescription, left, top, right, bottom, metadata); boolean old = mClickAreas.remove(car); mClickAreas.remove(car); mClickAreas.add(car); } /** * Called by commands to listen to touch events * * @param listener * @param listener touch listener */ public void addTouchListener(TouchListener listener) { public void addTouchListener(@NonNull TouchListener listener) { mTouchListeners.add(listener); } Loading Loading @@ -1090,9 +1126,7 @@ public class CoreDocument implements Serializable { } } for (IdActionCallback listener : mIdActionListeners) { listener.onAction(id, metadata); } notifyOfException(id, metadata); Component component = getComponent(id); if (component != null) { Loading @@ -1100,13 +1134,23 @@ public class CoreDocument implements Serializable { } } /** Warn click listeners when a click area is activated */ private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { /** * trigger host Actions on exception. Exception handler should be registered in header * * @param id id of the exception * @param metadata the exception string */ public void notifyOfException(int id, @Nullable String metadata) { for (IdActionCallback listener : mIdActionListeners) { listener.onAction(clickArea.mId, clickArea.mMetadata); listener.onAction(id, metadata); } } /** Warn click listeners when a click area is activated */ private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) { notifyOfException(clickArea.mId, clickArea.mMetadata); } /** * Returns true if the document has touch listeners * Loading @@ -1114,7 +1158,7 @@ public class CoreDocument implements Serializable { */ public boolean hasTouchListener() { boolean hasComponentsTouchListeners = mRootLayoutComponent != null && mRootLayoutComponent.hasTouchListeners(); mRootLayoutComponent != null && mRootLayoutComponent.getHasTouchListeners(); return hasComponentsTouchListeners || !mTouchListeners.isEmpty(); } Loading @@ -1125,7 +1169,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public boolean touchDrag(RemoteContext context, float x, float y) { public boolean touchDrag(@NonNull RemoteContext context, float x, float y) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1139,10 +1183,7 @@ public class CoreDocument implements Serializable { return true; } } if (!mTouchListeners.isEmpty()) { return true; } return false; return !mTouchListeners.isEmpty(); } /** Loading @@ -1151,7 +1192,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchDown(RemoteContext context, float x, float y) { public void touchDown(@NonNull RemoteContext context, float x, float y) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1169,7 +1210,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchUp(RemoteContext context, float x, float y, float dx, float dy) { public void touchUp(@NonNull RemoteContext context, float x, float y, float dx, float dy) { context.loadFloat(RemoteContext.ID_TOUCH_POS_X, x); context.loadFloat(RemoteContext.ID_TOUCH_POS_Y, y); for (TouchListener clickArea : mTouchListeners) { Loading @@ -1190,7 +1231,7 @@ public class CoreDocument implements Serializable { * @param x position of touch * @param y position of touch */ public void touchCancel(RemoteContext context, float x, float y, float dx, float dy) { public void touchCancel(@NonNull RemoteContext context, float x, float y, float dx, float dy) { if (mRootLayoutComponent != null) { for (Component component : mAppliedTouchOperations) { component.onTouchCancel(context, this, x, y, true); Loading Loading @@ -1226,7 +1267,7 @@ public class CoreDocument implements Serializable { * * @return array of named variables or null */ public String[] getNamedVariables(int type) { public @NonNull String [] getNamedVariables(int type) { ArrayList<String> ret = new ArrayList<>(); getNamedVars(type, mOperations, ret); return ret.toArray(new String[0]); Loading Loading @@ -1267,7 +1308,7 @@ public class CoreDocument implements Serializable { /** * Returns > 0 if it needs to repaint * * @return * @return 0 if needs to repaint */ public int needsRepaint() { return mRepaintNext; Loading @@ -1277,8 +1318,8 @@ public class CoreDocument implements Serializable { * Traverse the list of operations to update the variables. TODO: this should walk the * dependency tree instead * * @param context * @param operations * @param context the context * @param operations list of operations */ private void updateVariables( @NonNull RemoteContext context, int theme, List<Operation> operations) { Loading @@ -1303,6 +1344,7 @@ public class CoreDocument implements Serializable { */ public void paint(@NonNull RemoteContext context, int theme) { context.clearLastOpCount(); assert context.getPaintContext() != null; context.getPaintContext().clearNeedsRepaint(); context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity()); context.mMode = RemoteContext.ContextMode.UNSET; Loading Loading @@ -1331,8 +1373,8 @@ public class CoreDocument implements Serializable { float sw = mScaleOutput[0]; float sh = mScaleOutput[1]; computeTranslate(context.mWidth, context.mHeight, sw, sh, mTranslateOutput); context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]); context.mPaintContext.scale(sw, sh); context.getPaintContext().translate(mTranslateOutput[0], mTranslateOutput[1]); context.getPaintContext().scale(sw, sh); } else { // If not, we set the document width and height to be the current context width and // height. Loading Loading @@ -1407,23 +1449,22 @@ public class CoreDocument implements Serializable { int count = mOperations.size(); for (Operation mOperation : mOperations) { if (mOperation instanceof Component) { count += getChildOps((Component) mOperation); if (mOperation instanceof Container) { count += getChildOps((Container) mOperation); } } return count; } private int getChildOps(@NonNull Component base) { int count = base.mList.size(); for (Operation mOperation : base.mList) { if (mOperation instanceof Component) { private int getChildOps(@NonNull Container base) { int count = base.getList().size(); for (Operation operation : base.getList()) { if (operation instanceof Container) { int mult = 1; if (mOperation instanceof LoopOperation) { mult = ((LoopOperation) mOperation).estimateIterations(); if (operation instanceof LoopOperation) { mult = ((LoopOperation) operation).estimateIterations(); } count += mult * getChildOps((Component) mOperation); count += mult * getChildOps((Container) operation); } } return count; Loading @@ -1432,7 +1473,7 @@ public class CoreDocument implements Serializable { /** * Returns a list of useful statistics for the runtime document * * @return * @return array of strings representing some useful statistics */ @NonNull public String[] getStats() { Loading @@ -1440,8 +1481,8 @@ public class CoreDocument implements Serializable { WireBuffer buffer = new WireBuffer(); int count = mOperations.size(); HashMap<String, int[]> map = new HashMap<>(); for (Operation mOperation : mOperations) { Class<? extends Operation> c = mOperation.getClass(); for (Operation operation : mOperations) { Class<? extends Operation> c = operation.getClass(); int[] values; if (map.containsKey(c.getSimpleName())) { values = map.get(c.getSimpleName()); Loading @@ -1451,12 +1492,9 @@ public class CoreDocument implements Serializable { } values[0] += 1; values[1] += sizeOfComponent(mOperation, buffer); if (mOperation instanceof Container) { Container com = (Container) mOperation; count += addChildren(com, map, buffer); } else if (mOperation instanceof LoopOperation) { LoopOperation com = (LoopOperation) mOperation; values[1] += sizeOfComponent(operation, buffer); if (operation instanceof Container) { Container com = (Container) operation; count += addChildren(com, map, buffer); } } Loading Loading @@ -1503,7 +1541,7 @@ public class CoreDocument implements Serializable { * Returns a string representation of the operations, traversing the list of operations & * containers * * @return * @return representation of operations */ @NonNull public String toNestedString() { Loading Loading @@ -1545,7 +1583,7 @@ public class CoreDocument implements Serializable { * @param shader the source of the shader * @return true if the shader is allowed to run */ boolean isShaderValid(String shader); boolean isShaderValid(@NonNull String shader); } /** Loading @@ -1554,7 +1592,7 @@ public class CoreDocument implements Serializable { * @param context the remote context * @param ctl the call back to allow evaluation of shaders */ public void checkShaders(RemoteContext context, ShaderControl ctl) { public void checkShaders(@NonNull RemoteContext context, @NonNull ShaderControl ctl) { checkShaders(context, ctl, mOperations); } Loading @@ -1578,15 +1616,17 @@ public class CoreDocument implements Serializable { ShaderData sd = (ShaderData) op; int id = sd.getShaderTextId(); String str = context.getText(id); if (str != null) { sd.enable(ctl.isShaderValid(str)); } } } } /** * Set if this is an update doc * * @param isUpdateDoc * @param isUpdateDoc true if the doc represents update operations rather than a normal doc */ public void setUpdateDoc(boolean isUpdateDoc) { mIsUpdateDoc = isUpdateDoc; Loading
core/java/com/android/internal/widget/remotecompose/core/MatrixAccess.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * 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; import android.annotation.NonNull; import android.annotation.Nullable; import java.text.DecimalFormat; /** Support access to floats in matrix */ public interface MatrixAccess { /** * Get a the matrix * * @return the matrix */ @NonNull float [] get(); /** * Convert a 4x4 matrix to a 3x3 matrix * * @param matrix 4x4 matrix * @return 3x3 matrix */ static @Nullable float [] to3x3(@NonNull float [] matrix) { if (matrix.length == 16) { float[] matrix3x3 = new float[9]; float[] matrix4x4; matrix4x4 = matrix; matrix3x3[0] = matrix4x4[0]; matrix3x3[1] = matrix4x4[1]; matrix3x3[2] = matrix4x4[3]; // Column 1 matrix3x3[3] = matrix4x4[4]; matrix3x3[4] = matrix4x4[5]; matrix3x3[5] = matrix4x4[7]; // Column 2 matrix3x3[6] = matrix4x4[8]; matrix3x3[7] = matrix4x4[9]; matrix3x3[8] = matrix4x4[15]; // should be 1. Not sure about this return matrix3x3; } else if (matrix.length == 9) { return matrix; } return null; } /** * Dump a matrix to the console * * @param m matrix */ static void dump(@NonNull float [] m) { String str = ""; int step = m.length == 16 ? 4 : 3; DecimalFormat df = new DecimalFormat("0.00"); for (int i = 0; i < m.length; i++) { if (i % step == 0) { str += "\n"; } str += df.format(m[i]) + " "; } System.out.println(str); } }
core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java +1 −2 Original line number Diff line number Diff line Loading @@ -31,8 +31,7 @@ public interface OperationInterface { void apply(@NonNull RemoteContext context); /** Debug utility to display an operation + indentation */ @NonNull String deepToString(@NonNull String indent); @NonNull String deepToString(@NonNull String indent); /** * Returns true if the operation is marked as "dirty" Loading
core/java/com/android/internal/widget/remotecompose/core/Operations.java +277 −6 File changed.Preview size limit exceeded, changes collapsed. Show changes
core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +31 −7 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.Nullable; import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import java.time.Clock; import java.util.HashMap; /** Specify an abstract paint context used by RemoteCompose commands to draw */ Loading Loading @@ -75,6 +76,10 @@ public abstract class PaintContext { matrixSave(); } public @NonNull Clock getClock() { return mContext.getClock(); } /** * Draw a bitmap * Loading Loading @@ -213,7 +218,7 @@ public abstract class PaintContext { * * @param paint */ public abstract void replacePaint(PaintBundle paint); public abstract void replacePaint(@NonNull PaintBundle paint); /** * draw a round rect Loading Loading @@ -280,7 +285,7 @@ public abstract class PaintContext { * * @return an instance of a ComputedTextLayout (typically if complex text drawing is used) */ public abstract Platform.ComputedTextLayout layoutComplexText( public abstract @Nullable Platform.ComputedTextLayout layoutComplexText( int textId, int start, int end, Loading Loading @@ -317,7 +322,7 @@ public abstract class PaintContext { * * @param computedTextLayout pre-computed text layout */ public abstract void drawComplexText(Platform.ComputedTextLayout computedTextLayout); public abstract void drawComplexText(@Nullable Platform.ComputedTextLayout computedTextLayout); /** * Draw an interpolation between two paths Loading Loading @@ -446,7 +451,7 @@ public abstract class PaintContext { * @return true if in debug mode, false otherwise */ public boolean isDebug() { return mContext.isDebug(); return mContext.isBasicDebug(); } /** Loading Loading @@ -497,10 +502,10 @@ public abstract class PaintContext { /** * Returns a String from an id * * @param textID * @param textId * @return the string if found */ public abstract @Nullable String getText(int textID); public abstract @Nullable String getText(int textId); /** * Returns true if the document has been encoded for at least the given version MAJOR.MINOR Loading @@ -513,4 +518,23 @@ public abstract class PaintContext { public boolean supportsVersion(int major, int minor, int patch) { return mContext.supportsVersion(major, minor, patch); } /** * Sets the Matrix from the path * * @param pathId id of the path * @param fraction fractional position in the path to use * @param vOffset vertical offset * @param flags flags */ public abstract void matrixFromPath(int pathId, float fraction, float vOffset, int flags); /** * Redirect drawing to a bitmap (0 = back to main canvas) * * @param bitmapId id of bitmap to draw to or 0 to draw to the canvas * @param mode flags support init of bitmap 0 = clear to color, 1 = no clear * @param color set the initial color of the bitmap */ public abstract void drawToBitmap(int bitmapId, int mode, int color); }