diff options
7 files changed, 256 insertions, 8 deletions
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 766fbf1a80f5..8fbd10c25995 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -64,16 +64,16 @@ public class CoreDocument implements Serializable { private static final boolean DEBUG = false; // Semantic version - public static final int MAJOR_VERSION = 0; - public static final int MINOR_VERSION = 4; + public static final int MAJOR_VERSION = 1; + public static final int MINOR_VERSION = 0; public static final int PATCH_VERSION = 0; // Internal version level - public static final int DOCUMENT_API_LEVEL = 4; + public static final int DOCUMENT_API_LEVEL = 5; // We also keep a more fine-grained BUILD number, exposed as // ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD - static final float BUILD = 0.7f; + static final float BUILD = 0.0f; private static final boolean UPDATE_VARIABLES_BEFORE_LAYOUT = false; diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index add9d5bae552..20252366e264 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -30,6 +30,7 @@ import com.android.internal.widget.remotecompose.core.operations.DataListFloat; import com.android.internal.widget.remotecompose.core.operations.DataListIds; import com.android.internal.widget.remotecompose.core.operations.DataMapIds; import com.android.internal.widget.remotecompose.core.operations.DataMapLookup; +import com.android.internal.widget.remotecompose.core.operations.DebugMessage; import com.android.internal.widget.remotecompose.core.operations.DrawArc; import com.android.internal.widget.remotecompose.core.operations.DrawBitmap; import com.android.internal.widget.remotecompose.core.operations.DrawBitmapFontText; @@ -231,6 +232,7 @@ public class Operations { public static final int PATH_COMBINE = 175; public static final int HAPTIC_FEEDBACK = 177; public static final int CONDITIONAL_OPERATIONS = 178; + public static final int DEBUG_MESSAGE = 179; ///////////////////////////////////////// ====================== @@ -443,6 +445,7 @@ public class Operations { map.put(PATH_COMBINE, PathCombine::read); map.put(HAPTIC_FEEDBACK, HapticFeedback::read); map.put(CONDITIONAL_OPERATIONS, ConditionalOperations::read); + map.put(DEBUG_MESSAGE, DebugMessage::read); // map.put(ACCESSIBILITY_CUSTOM_ACTION, CoreSemantics::read); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index 1f026687680f..a86b62e2caa3 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -33,6 +33,7 @@ import com.android.internal.widget.remotecompose.core.operations.DataListFloat; import com.android.internal.widget.remotecompose.core.operations.DataListIds; import com.android.internal.widget.remotecompose.core.operations.DataMapIds; import com.android.internal.widget.remotecompose.core.operations.DataMapLookup; +import com.android.internal.widget.remotecompose.core.operations.DebugMessage; import com.android.internal.widget.remotecompose.core.operations.DrawArc; import com.android.internal.widget.remotecompose.core.operations.DrawBitmap; import com.android.internal.widget.remotecompose.core.operations.DrawBitmapFontText; @@ -1332,7 +1333,7 @@ public class RemoteComposeBuffer { * @return the nan id of float */ public float reserveFloatVariable() { - int id = mRemoteComposeState.cacheFloat(0f); + int id = mRemoteComposeState.nextId(); return Utils.asNan(id); } @@ -1870,6 +1871,46 @@ public class RemoteComposeBuffer { } /** + * Add a scroll modifier + * + * @param direction HORIZONTAL(0) or VERTICAL(1) + * @param positionId the position id as a NaN + */ + public void addModifierScroll(int direction, float positionId) { + float max = this.reserveFloatVariable(); + float notchMax = this.reserveFloatVariable(); + float touchExpressionDirection = + direction != 0 ? RemoteContext.FLOAT_TOUCH_POS_X : RemoteContext.FLOAT_TOUCH_POS_Y; + + ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax); + this.addTouchExpression( + positionId, + 0f, + 0f, + max, + 0f, + 3, + new float[] { + touchExpressionDirection, -1, MUL, + }, + TouchExpression.STOP_GENTLY, + null, + null); + ContainerEnd.apply(mBuffer); + } + + /** + * Add a scroll modifier + * + * @param direction HORIZONTAL(0) or VERTICAL(1) + */ + public void addModifierScroll(int direction) { + float max = this.reserveFloatVariable(); + ScrollModifierOperation.apply(mBuffer, direction, 0f, max, 0f); + ContainerEnd.apply(mBuffer); + } + + /** * Add a background modifier of provided color * * @param color the color of the background @@ -2464,4 +2505,15 @@ public class RemoteComposeBuffer { public void addConditionalOperations(byte type, float a, float b) { ConditionalOperations.apply(mBuffer, type, a, b); } + + /** + * Add a debug message + * + * @param textId text id + * @param value + * @param flags + */ + public void addDebugMessage(int textId, float value, int flags) { + DebugMessage.apply(mBuffer, textId, value, flags); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DebugMessage.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DebugMessage.java new file mode 100644 index 000000000000..c27bd8b577bf --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DebugMessage.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import android.annotation.NonNull; + +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.VariableSupport; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; +import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation; + +import java.util.List; + +/** + * This prints debugging message useful for debugging. It should not be use in production documents + */ +public class DebugMessage extends Operation implements VariableSupport { + private static final int OP_CODE = Operations.DEBUG_MESSAGE; + private static final String CLASS_NAME = "DebugMessage"; + int mTextID; + float mFloatValue; + float mOutFloatValue; + int mFlags = 0; + + public DebugMessage(int textID, float value, int flags) { + mTextID = textID; + mFloatValue = value; + mFlags = flags; + } + + @Override + public void updateVariables(@NonNull RemoteContext context) { + System.out.println("Debug message : updateVariables "); + mOutFloatValue = + Float.isNaN(mFloatValue) + ? context.getFloat(Utils.idFromNan(mFloatValue)) + : mFloatValue; + System.out.println( + "Debug message : updateVariables " + + Utils.floatToString(mFloatValue, mOutFloatValue)); + } + + @Override + public void registerListening(@NonNull RemoteContext context) { + System.out.println("Debug message : registerListening "); + + if (Float.isNaN(mFloatValue)) { + System.out.println("Debug message : registerListening " + mFloatValue); + context.listensTo(Utils.idFromNan(mFloatValue), this); + } + } + + @Override + public void write(@NonNull WireBuffer buffer) { + apply(buffer, mTextID, mFloatValue, mFlags); + } + + @NonNull + @Override + public String toString() { + return "DebugMessage " + + mTextID + + ", " + + Utils.floatToString(mFloatValue, mOutFloatValue) + + ", " + + mFlags; + } + + /** + * Read this operation and add it to the list of operations + * + * @param buffer the buffer to read + * @param operations the list of operations that will be added to + */ + public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) { + int text = buffer.readInt(); + float floatValue = buffer.readFloat(); + int flags = buffer.readInt(); + DebugMessage op = new DebugMessage(text, floatValue, flags); + operations.add(op); + } + + /** + * The name of the class + * + * @return the name + */ + @NonNull + public static String name() { + return CLASS_NAME; + } + + /** + * The OP_CODE for this command + * + * @return the opcode + */ + public static int id() { + return OP_CODE; + } + + /** + * Writes out the operation to the buffer + * + * @param buffer write the command to the buffer + * @param textID id of the text + * @param value value to print + * @param flags flags to print + */ + public static void apply(@NonNull WireBuffer buffer, int textID, float value, int flags) { + buffer.start(OP_CODE); + buffer.writeInt(textID); + buffer.writeFloat(value); + buffer.writeInt(flags); + } + + /** + * Populate the documentation with a description of this operation + * + * @param doc to append the description to. + */ + public static void documentation(@NonNull DocumentationBuilder doc) { + doc.operation("DebugMessage Operations", id(), CLASS_NAME) + .description("Print debugging messages") + .field(DocumentedOperation.INT, "textId", "test to print") + .field(DocumentedOperation.FLOAT, "value", "value of a float to print") + .field(DocumentedOperation.INT, "flags", "print additional information"); + } + + @Override + public void apply(@NonNull RemoteContext context) { + String str = context.getText(mTextID); + System.out.println("Debug message : " + str + " " + mOutFloatValue + " " + mFlags); + } + + @NonNull + @Override + public String deepToString(@NonNull String indent) { + return indent + toString(); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java index dee79a45de3d..67d3a6584897 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TimeAttribute.java @@ -266,10 +266,12 @@ public class TimeAttribute extends PaintOperation { case TIME_FROM_NOW_SEC: case TIME_FROM_ARG_SEC: ctx.loadFloat(mId, (delta) * 1E-3f); + ctx.needsRepaint(); break; case TIME_FROM_ARG_MIN: case TIME_FROM_NOW_MIN: ctx.loadFloat(mId, (float) (delta * 1E-3 / 60)); + ctx.needsRepaint(); break; case TIME_FROM_ARG_HR: case TIME_FROM_NOW_HR: @@ -298,6 +300,7 @@ public class TimeAttribute extends PaintOperation { break; case TIME_FROM_LOAD_SEC: ctx.loadFloat(mId, (value - load_time) * 1E-3f); + ctx.needsRepaint(); break; } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java index f24672922367..3e5dff8ad277 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java @@ -494,7 +494,7 @@ public class TouchExpression extends Operation mTouchUpTime = context.getAnimationTime(); float dest = getStopPosition(value, slope); - float time = mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity); + float time = Math.min(2, mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity)); mEasyTouch.config(value, dest, slope, time, mMaxAcceleration, mMaxVelocity, null); mEasingToStop = true; context.needsRepaint(); diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java index 17f4fc82af5f..e76fb0654df6 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java @@ -42,6 +42,9 @@ import java.util.Set; public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachStateChangeListener { static final boolean USE_VIEW_AREA_CLICK = true; // Use views to represent click areas + static final float DEFAULT_FRAME_RATE = 60f; + static final float POST_TO_NEXT_FRAME_THRESHOLD = 60f; + RemoteComposeDocument mDocument = null; int mTheme = Theme.LIGHT; boolean mInActionDown = false; @@ -53,9 +56,11 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta long mStart = System.nanoTime(); long mLastFrameDelay = 1; - float mMaxFrameRate = 60f; // frames per seconds + float mMaxFrameRate = DEFAULT_FRAME_RATE; // frames per seconds long mMaxFrameDelay = (long) (1000 / mMaxFrameRate); + long mLastFrameCall = System.currentTimeMillis(); + private Choreographer mChoreographer; private Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @@ -100,6 +105,7 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta public void setDocument(RemoteComposeDocument value) { mDocument = value; + mMaxFrameRate = DEFAULT_FRAME_RATE; mDocument.initializeContext(mARContext); mDisable = false; mARContext.setDocLoadTime(); @@ -546,8 +552,25 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta } int nextFrame = mDocument.needsRepaint(); if (nextFrame > 0) { - mLastFrameDelay = Math.max(mMaxFrameDelay, nextFrame); + if (mMaxFrameRate >= POST_TO_NEXT_FRAME_THRESHOLD) { + mLastFrameDelay = nextFrame; + } else { + mLastFrameDelay = Math.max(mMaxFrameDelay, nextFrame); + } if (mChoreographer != null) { + if (mDebug == 1) { + System.err.println( + "RC : POST CHOREOGRAPHER WITH " + + mLastFrameDelay + + " (nextFrame was " + + nextFrame + + ", max delay " + + mMaxFrameDelay + + ", " + + " max framerate is " + + mMaxFrameRate + + ")"); + } mChoreographer.postFrameCallbackDelayed(mFrameCallback, mLastFrameDelay); } if (!mARContext.useChoreographer()) { @@ -567,6 +590,16 @@ public class RemoteComposeCanvas extends FrameLayout implements View.OnAttachSta mDisable = true; invalidate(); } + if (mDebug == 1) { + long frameDelay = System.currentTimeMillis() - mLastFrameCall; + System.err.println( + "RC : Delay since last frame " + + frameDelay + + " ms (" + + (1000f / (float) frameDelay) + + " fps)"); + mLastFrameCall = System.currentTimeMillis(); + } } private void drawDisable(Canvas canvas) { |