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

Commit 005926f0 authored by Nicolas Roard's avatar Nicolas Roard Committed by Android (Google) Code Review
Browse files

Merge "Update to ToT RemoteCompose" into main

parents 0f27b315 6b3645c1
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -27,9 +27,5 @@ public interface CompanionOperation {
     * @param operations command is to be added
     */
    void read(WireBuffer buffer, List<Operation> operations);

    // Debugging / Documentation utility functions
    String name();
    int id();
}
+230 −11
Original line number Diff line number Diff line
@@ -15,16 +15,23 @@
 */
package com.android.internal.widget.remotecompose.core;

import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.layout.ComponentEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.ComponentStartOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ComponentModifiers;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

@@ -34,6 +41,8 @@ import java.util.Set;
 */
public class CoreDocument {

    private static final boolean DEBUG = false;

    ArrayList<Operation> mOperations;

    RootLayoutComponent mRootLayoutComponent = null;
@@ -57,6 +66,8 @@ public class CoreDocument {

    RemoteComposeBuffer mBuffer = new RemoteComposeBuffer(mRemoteComposeState);

    private int mLastId = 1; // last component id when inflating the file

    public String getContentDescription() {
        return mContentDescription;
    }
@@ -303,6 +314,59 @@ public class CoreDocument {
        return null;
    }

    /**
     * Returns a string representation of the component hierarchy of the document
     *
     * @return a standardized string representation of the component hierarchy
     */
    public String displayHierarchy() {
        StringSerializer serializer = new StringSerializer();
        for (Operation op : mOperations) {
            if (op instanceof RootLayoutComponent) {
                ((RootLayoutComponent) op).displayHierarchy((Component) op, 0, serializer);
            } else if (op instanceof SerializableToString) {
                ((SerializableToString) op).serializeToString(0, serializer);
            }
        }
        return serializer.toString();
    }

    /**
     * Callback interface for host actions
     */
    public interface ActionCallback {
        // TODO: add payload support
        void onAction(String name);
    }

    HashSet<ActionCallback> mActionListeners = new HashSet<ActionCallback>();

    /**
     * Warn action listeners for the given named action
     * @param name the action name
     */
    public void runNamedAction(String name) {
        for (ActionCallback callback : mActionListeners) {
            callback.onAction(name);
        }
    }

    /**
     * Add a callback for handling the named host actions
     *
     * @param callback
     */
    public void addActionCallback(ActionCallback callback) {
        mActionListeners.add(callback);
    }

    /**
     * Clear existing callbacks for named host actions
     */
    public void clearActionCallbacks() {
        mActionListeners.clear();
    }

    public interface ClickCallbacks {
        void click(int id, String metadata);
    }
@@ -403,7 +467,7 @@ public class CoreDocument {
            }
        }
        if (mRootLayoutComponent != null) {
            mRootLayoutComponent.assignIds();
            mRootLayoutComponent.assignIds(mLastId);
        }
    }

@@ -417,7 +481,9 @@ public class CoreDocument {
        ArrayList<Component> components = new ArrayList<>();
        ArrayList<Operation> finalOperationsList = new ArrayList<>();
        ArrayList<Operation> ops = finalOperationsList;
        ClickModifierOperation currentClickModifier = null;

        mLastId = -1;
        for (Operation o : operations) {
            if (o instanceof ComponentStartOperation) {
                Component component = (Component) o;
@@ -426,6 +492,9 @@ public class CoreDocument {
                currentComponent = component;
                ops.add(currentComponent);
                ops = currentComponent.getList();
                if (component.getComponentId() < mLastId) {
                    mLastId = component.getComponentId();
                }
            } else if (o instanceof ComponentEnd) {
                if (currentComponent instanceof LayoutComponent) {
                    ((LayoutComponent) currentComponent).inflate();
@@ -437,6 +506,14 @@ public class CoreDocument {
                } else {
                    ops = finalOperationsList;
                }
            } else if (o instanceof ClickModifierOperation) {
                // TODO: refactor to add container <- component...
                currentClickModifier = (ClickModifierOperation) o;
                ops = ((ClickModifierOperation) o).getList();
            } else if (o instanceof ClickModifierEnd) {
                ops = currentComponent.getList();
                ops.add(currentClickModifier);
                currentClickModifier = null;
            } else {
                ops.add(o);
            }
@@ -444,12 +521,46 @@ public class CoreDocument {
        return ops;
    }

    private HashMap<Integer, Component> mComponentMap = new HashMap<Integer, Component>();

    private void registerVariables(RemoteContext context, ArrayList<Operation> list) {
        for (Operation op : list) {
            if (op instanceof VariableSupport) {
                ((VariableSupport) op).updateVariables(context);
                ((VariableSupport) op).registerListening(context);
            }
            if (op instanceof Component) {
                mComponentMap.put(((Component) op).getComponentId(), (Component) op);
                registerVariables(context, ((Component) op).getList());
            }
            if (op instanceof ComponentValue) {
                ComponentValue v = (ComponentValue) op;
                Component component = mComponentMap.get(v.getComponentId());
                if (component != null) {
                    component.addComponentValue(v);
                } else {
                    System.out.println("=> Component not found for id " + v.getComponentId());
                }
            }
            if (op instanceof ComponentModifiers) {
                for (ModifierOperation modifier : ((ComponentModifiers) op).getList()) {
                    if (modifier instanceof VariableSupport) {
                        ((VariableSupport) modifier).updateVariables(context);
                        ((VariableSupport) modifier).registerListening(context);
                    }
                }
            }
            op.apply(context);
        }
    }

    /**
     * Called when an initialization is needed, allowing the document to eg load
     * resources / cache them.
     */
    public void initializeContext(RemoteContext context) {
        mRemoteComposeState.reset();
        mRemoteComposeState.setContext(context);
        mClickAreas.clear();
        mRemoteComposeState.setNextId(RemoteComposeState.START_ID);
        context.mDocument = this;
@@ -458,15 +569,8 @@ public class CoreDocument {
        context.mMode = RemoteContext.ContextMode.DATA;
        mTimeVariables.updateTime(context);

        for (Operation op : mOperations) {
            if (op instanceof VariableSupport) {
                ((VariableSupport) op).updateVariables(context);
                ((VariableSupport) op).registerListening(context);
            }
            op.apply(context);
        }
        registerVariables(context, mOperations);
        context.mMode = RemoteContext.ContextMode.UNSET;

    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -528,16 +632,28 @@ public class CoreDocument {
        mClickListeners.add(callback);
    }

    /**
     * Returns the list of set click listeners
     *
     * @return set of click listeners
     */
    public HashSet<CoreDocument.ClickCallbacks> getClickListeners() {
        return mClickListeners;
    }

    /**
     * Passing a click event to the document. This will possibly result in calling the click
     * listeners.
     */
    public void onClick(float x, float y) {
    public void onClick(RemoteContext context, float x, float y) {
        for (ClickAreaRepresentation clickArea : mClickAreas) {
            if (clickArea.contains(x, y)) {
                warnClickListeners(clickArea);
            }
        }
        if (mRootLayoutComponent != null) {
            mRootLayoutComponent.onClick(context, this, x, y);
        }
    }

    /**
@@ -551,6 +667,9 @@ public class CoreDocument {
                warnClickListeners(clickArea);
            }
        }
        for (ClickCallbacks listener : mClickListeners) {
            listener.click(id, "");
        }
    }

    /**
@@ -627,13 +746,17 @@ public class CoreDocument {
     * @param theme   the theme we want to use for this document.
     */
    public void paint(RemoteContext context, int theme) {
        context.mMode = RemoteContext.ContextMode.PAINT;
        long time = System.nanoTime();
        context.getPaintContext().clearNeedsRepaint();
        context.mMode = RemoteContext.ContextMode.UNSET;

        // current theme starts as UNSPECIFIED, until a Theme setter
        // operation gets executed and modify it.
        context.setTheme(Theme.UNSPECIFIED);

        context.mRemoteComposeState = mRemoteComposeState;
        context.mRemoteComposeState.setContext(context);

        if (mContentSizing == RootContentBehavior.SIZING_SCALE) {
            // we need to add canvas transforms ops here
            computeScale(context.mWidth, context.mHeight, mScaleOutput);
@@ -654,10 +777,19 @@ public class CoreDocument {
            if (mRootLayoutComponent.needsMeasure()) {
                mRootLayoutComponent.layout(context);
            }
            // TODO -- this should be specifically about applying animation, not paint
            mRootLayoutComponent.paint(context.getPaintContext());
            // TODO -- should be able to remove this
            mRootLayoutComponent.updateVariables(context);
            if (DEBUG) {
                String hierarchy = mRootLayoutComponent.displayHierarchy();
                System.out.println(hierarchy);
            }
            if (mRootLayoutComponent.doesNeedsRepaint()) {
                mRepaintNext = 1;
            }
        }
        context.mMode = RemoteContext.ContextMode.PAINT;
        for (Operation op : mOperations) {
            // operations will only be executed if no theme is set (ie UNSPECIFIED)
            // or the theme is equal as the one passed in argument to paint.
@@ -671,8 +803,95 @@ public class CoreDocument {
                op.apply(context);
            }
        }
        if (context.getPaintContext().doesNeedsRepaint()
                || (mRootLayoutComponent != null && mRootLayoutComponent.doesNeedsRepaint())) {
            mRepaintNext = 1;
        }
        context.mMode = RemoteContext.ContextMode.UNSET;
       // System.out.println(">>   " + (  System.nanoTime() - time)*1E-6f+" ms");
    }

    public String[] getStats() {
        ArrayList<String> ret = new ArrayList<>();
        WireBuffer buffer = new WireBuffer();
        int count = mOperations.size();
        HashMap<String, int[]> map = new HashMap<>();
        for (Operation mOperation : mOperations) {
            Class<? extends Operation> c = mOperation.getClass();
            int[] values;
            if (map.containsKey(c.getSimpleName())) {
                values = map.get(c.getSimpleName());
            } else {
                values = new int[2];
                map.put(c.getSimpleName(), values);
            }

            values[0] += 1;
            values[1] += sizeOfComponent(mOperation, buffer);
            if (mOperation instanceof Component) {
                Component com = (Component) mOperation;
                count += addChildren(com, map, buffer);

            }
        }

        ret.add(0, "number of operations : " + count);

        for (String s : map.keySet()) {
            int[] v = map.get(s);
            ret.add(s + " : " + v[0] + ":" + v[1]);
        }
        return ret.toArray(new String[0]);
    }

    private int sizeOfComponent(Operation com, WireBuffer tmp) {
        tmp.reset(100);
        com.write(tmp);
        int size = tmp.getSize();
        tmp.reset(100);
        return size;
    }

    private int addChildren(Component base, HashMap<String, int[]> map, WireBuffer tmp) {
        int count = base.mList.size();
        for (Operation mOperation : base.mList) {
            Class<? extends Operation> c = mOperation.getClass();
            int[] values;
            if (map.containsKey(c.getSimpleName())) {
                values = map.get(c.getSimpleName());
            } else {
                values = new int[2];
                map.put(c.getSimpleName(), values);
            }
            values[0] += 1;
            values[1] += sizeOfComponent(mOperation, tmp);
            if (mOperation instanceof Component) {
                count += addChildren((Component) mOperation, map, tmp);
            }
        }
        return count;
    }

    public String toNestedString() {
        StringBuilder ret = new StringBuilder();
        for (Operation mOperation : mOperations) {
            ret.append(mOperation.toString());
            ret.append("\n");
            if (mOperation instanceof Component) {
                toNestedString((Component) mOperation, ret, "  ");
            }
        }
        return ret.toString();
    }

    private void toNestedString(Component base, StringBuilder ret, String indent) {
        for (Operation mOperation : base.mList) {
            ret.append(mOperation.toString());
            ret.append("\n");
            if (mOperation instanceof Component) {
                toNestedString((Component) mOperation, ret, indent + "  ");
            }
        }
    }
}
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.widget.remotecompose.core;

import com.android.internal.widget.remotecompose.core.documentation.DocumentedCompanionOperation;

public interface DocumentedCompanion extends CompanionOperation , DocumentedCompanionOperation {

}
+121 −61

File changed.

Preview size limit exceeded, changes collapsed.

+20 −3
Original line number Diff line number Diff line
@@ -21,12 +21,23 @@ import com.android.internal.widget.remotecompose.core.operations.paint.PaintBund
 * Specify an abstract paint context used by RemoteCompose commands to draw
 */
public abstract class PaintContext {
    protected RemoteContext mContext;
    public static final int TEXT_MEASURE_MONOSPACE_WIDTH = 0x01;
    public static final int TEXT_MEASURE_FONT_HEIGHT = 0x02;

    protected RemoteContext mContext;
    private boolean mNeedsRepaint = false;
    public RemoteContext getContext() {
        return mContext;
    }

    public boolean doesNeedsRepaint() {
        return mNeedsRepaint;
    }

    public void clearNeedsRepaint() {
        mNeedsRepaint = false;
    }

    public PaintContext(RemoteContext context) {
        this.mContext = context;
    }
@@ -111,13 +122,16 @@ public abstract class PaintContext {
     * @param textId
     * @param start
     * @param end    if end is -1 it means the whole string
     * @param monospace measure with better support for monospace
     * @param flags how to measure:
     *              TEXT_MEASURE_MONOSPACE_WIDTH - measure as a monospace font
     *              TEXT_MEASURE_FULL_HEIGHT - measure bounds of the given string using the
     *                max ascend and descent of the font (not just of the measured text)
     * @param bounds the bounds (left, top, right, bottom)
     */
    public abstract void getTextBounds(int textId,
                                       int start,
                                       int end,
                                       boolean monospace,
                                       int flags,
                                       float[]bounds);

    /**
@@ -267,5 +281,8 @@ public abstract class PaintContext {
        System.out.println("[LOG] " + content);
    }

    public void needsRepaint() {
        mNeedsRepaint = true;
    }
}
Loading