Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06261495 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update to ToT RemoteCompose" into main

parents 1be1b1f2 a5750857
Loading
Loading
Loading
Loading
+113 −73
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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
@@ -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() {
@@ -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() {
@@ -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)
@@ -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;
    }

@@ -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;
        }
@@ -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>();
@@ -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);
    }
@@ -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;
    }

@@ -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);
    }

@@ -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>();
@@ -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);
@@ -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);
@@ -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) {
@@ -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) {
@@ -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);
    }

@@ -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) {
@@ -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
     *
@@ -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();
    }

@@ -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) {
@@ -1139,10 +1183,7 @@ public class CoreDocument implements Serializable {
                return true;
            }
        }
        if (!mTouchListeners.isEmpty()) {
            return true;
        }
        return false;
        return !mTouchListeners.isEmpty();
    }

    /**
@@ -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) {
@@ -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) {
@@ -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);
@@ -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]);
@@ -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;
@@ -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) {
@@ -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;
@@ -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.
@@ -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;
@@ -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() {
@@ -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());
@@ -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);
            }
        }
@@ -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() {
@@ -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);
    }

    /**
@@ -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);
    }

@@ -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;
+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);
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -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"
+277 −6

File changed.

Preview size limit exceeded, changes collapsed.

+31 −7
Original line number Diff line number Diff line
@@ -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 */
@@ -75,6 +76,10 @@ public abstract class PaintContext {
        matrixSave();
    }

    public @NonNull Clock getClock() {
        return mContext.getClock();
    }

    /**
     * Draw a bitmap
     *
@@ -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
@@ -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,
@@ -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
@@ -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();
    }

    /**
@@ -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
@@ -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