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

Commit a5750857 authored by Nicolas Roard's avatar Nicolas Roard
Browse files

Update to ToT RemoteCompose

bug: 412684851
Flag: EXEMPT External Libraries
Test: in GoB
Change-Id: Ic73248e27359b2b9d9189081d921ee4e093fb809
parent 7f48fbe0
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