Merge "Update to ToT RemoteCompose" into main
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
new file mode 100644
index 0000000..410e021
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
@@ -0,0 +1,171 @@
+/*
+ * 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.accessibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
+
+import java.util.List;
+
+public class AndroidPlatformSemanticNodeApplier
+ implements SemanticNodeApplier<AccessibilityNodeInfo, Component, AccessibilitySemantics> {
+
+ private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription";
+
+ @Override
+ public void applyComponent(
+ @NonNull
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility,
+ AccessibilityNodeInfo nodeInfo,
+ Component component,
+ List<AccessibilitySemantics> semantics) {
+ if (component instanceof AccessibleComponent) {
+ applyContentDescription(
+ ((AccessibleComponent) component).getContentDescriptionId(),
+ nodeInfo,
+ remoteComposeAccessibility);
+
+ applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
+ }
+
+ applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
+
+ float[] locationInWindow = new float[2];
+ component.getLocationInWindow(locationInWindow);
+ Rect bounds =
+ new Rect(
+ (int) locationInWindow[0],
+ (int) locationInWindow[1],
+ (int) (locationInWindow[0] + component.getWidth()),
+ (int) (locationInWindow[1] + component.getHeight()));
+ //noinspection deprecation
+ nodeInfo.setBoundsInParent(bounds);
+ nodeInfo.setBoundsInScreen(bounds);
+
+ if (component instanceof AccessibleComponent) {
+ applyContentDescription(
+ ((AccessibleComponent) component).getContentDescriptionId(),
+ nodeInfo,
+ remoteComposeAccessibility);
+
+ applyText(
+ ((AccessibleComponent) component).getTextId(),
+ nodeInfo,
+ remoteComposeAccessibility);
+
+ applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
+ }
+
+ applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
+
+ if (nodeInfo.getText() == null && nodeInfo.getContentDescription() == null) {
+ nodeInfo.setContentDescription("");
+ }
+ }
+
+ public void applySemantics(
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility,
+ AccessibilityNodeInfo nodeInfo,
+ List<AccessibilitySemantics> semantics) {
+ for (AccessibilitySemantics semantic : semantics) {
+ if (semantic.isInterestingForSemantics()) {
+ if (semantic instanceof CoreSemantics) {
+ applyCoreSemantics(
+ remoteComposeAccessibility, nodeInfo, (CoreSemantics) semantic);
+ } else if (semantic instanceof AccessibleComponent) {
+ AccessibleComponent s = (AccessibleComponent) semantic;
+
+ applyContentDescription(
+ s.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
+
+ applyRole(s.getRole(), nodeInfo);
+
+ applyText(s.getTextId(), nodeInfo, remoteComposeAccessibility);
+
+ if (s.isClickable()) {
+ nodeInfo.setClickable(true);
+ nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
+ }
+ }
+ }
+ }
+ }
+
+ private void applyCoreSemantics(
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility,
+ AccessibilityNodeInfo nodeInfo,
+ CoreSemantics semantics) {
+ applyContentDescription(
+ semantics.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
+
+ applyRole(semantics.getRole(), nodeInfo);
+
+ applyText(semantics.getTextId(), nodeInfo, remoteComposeAccessibility);
+
+ applyStateDescription(
+ semantics.getStateDescriptionId(), nodeInfo, remoteComposeAccessibility);
+
+ nodeInfo.setEnabled(semantics.mEnabled);
+ }
+
+ void applyRole(@Nullable AccessibleComponent.Role role, AccessibilityNodeInfo nodeInfo) {
+ if (role != null) {
+ nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, role.getDescription());
+ }
+ }
+
+ void applyContentDescription(
+ @Nullable Integer contentDescriptionId,
+ AccessibilityNodeInfo nodeInfo,
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility) {
+ if (contentDescriptionId != null) {
+ nodeInfo.setContentDescription(
+ remoteComposeAccessibility.stringValue(contentDescriptionId));
+ }
+ }
+
+ void applyText(
+ @Nullable Integer textId,
+ AccessibilityNodeInfo nodeInfo,
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility) {
+ if (textId != null) {
+ nodeInfo.setText(remoteComposeAccessibility.stringValue(textId));
+ }
+ }
+
+ void applyStateDescription(
+ @Nullable Integer stateDescriptionId,
+ AccessibilityNodeInfo nodeInfo,
+ RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
+ remoteComposeAccessibility) {
+ if (stateDescriptionId != null) {
+ nodeInfo.setStateDescription(
+ remoteComposeAccessibility.stringValue(stateDescriptionId));
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java
new file mode 100644
index 0000000..66a7f02
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java
@@ -0,0 +1,182 @@
+/*
+ * 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.accessibility;
+
+import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Bundle;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+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.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.semantics.AccessibilitySemantics;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Java Player implementation of the {@link RemoteComposeDocumentAccessibility} interface. Each item
+ * in the semantic tree is a {@link Component} from the remote Compose UI. Each Component can have a
+ * list of modifiers that must be tagged with {@link AccessibilitySemantics} either incidentally
+ * (see {@link ClickModifierOperation}) or explicitly (see {@link CoreSemantics}).
+ */
+public class CoreDocumentAccessibility
+ implements RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics> {
+ private final CoreDocument mDocument;
+
+ private final Rect mMissingBounds = new Rect(0, 0, 1, 1);
+
+ public CoreDocumentAccessibility(CoreDocument document) {
+ this.mDocument = document;
+ }
+
+ @Nullable
+ @Override
+ public Integer getComponentIdAt(PointF point) {
+ return RootId;
+ }
+
+ @Override
+ public @Nullable Component findComponentById(int virtualViewId) {
+ RootLayoutComponent root = mDocument.getRootLayoutComponent();
+
+ if (root == null || virtualViewId == -1) {
+ return root;
+ }
+
+ return componentStream(root)
+ .filter(op -> op.getComponentId() == virtualViewId)
+ .findFirst()
+ .orElse(null);
+ }
+
+ @Override
+ public List<CoreSemantics.Mode> mergeMode(Component component) {
+ if (!(component instanceof LayoutComponent)) {
+ return Collections.singletonList(CoreSemantics.Mode.SET);
+ }
+
+ return ((LayoutComponent) component)
+ .getComponentModifiers().getList().stream()
+ .filter(i -> i instanceof AccessibleComponent)
+ .map(i -> ((AccessibleComponent) i).getMode())
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public boolean performAction(Component component, int action, Bundle arguments) {
+ if (action == ACTION_CLICK) {
+ mDocument.performClick(component.getComponentId());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Nullable
+ @Override
+ public String stringValue(int id) {
+ Object value = mDocument.getRemoteComposeState().getFromId(id);
+ return value != null ? String.valueOf(value) : null;
+ }
+
+ @Override
+ public List<AccessibilitySemantics> semanticModifiersForComponent(Component component) {
+ if (!(component instanceof LayoutComponent)) {
+ return Collections.emptyList();
+ }
+
+ List<ModifierOperation> modifiers =
+ ((LayoutComponent) component).getComponentModifiers().getList();
+
+ return modifiers.stream()
+ .filter(
+ it ->
+ it instanceof AccessibilitySemantics
+ && ((AccessibilitySemantics) it)
+ .isInterestingForSemantics())
+ .map(i -> (AccessibilitySemantics) i)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<Integer> semanticallyRelevantChildComponents(Component component) {
+ return componentStream(component)
+ .filter(i -> i.getComponentId() != component.getComponentId())
+ .filter(CoreDocumentAccessibility::isInteresting)
+ .map(Component::getComponentId)
+ .collect(Collectors.toList());
+ }
+
+ static Stream<Component> componentStream(Component root) {
+ return Stream.concat(
+ Stream.of(root),
+ root.mList.stream()
+ .flatMap(
+ op -> {
+ if (op instanceof Component) {
+ return componentStream((Component) op);
+ } else {
+ return Stream.empty();
+ }
+ }));
+ }
+
+ static Stream<ModifierOperation> modifiersStream(Component component) {
+ return component.mList.stream()
+ .filter(it -> it instanceof ComponentModifiers)
+ .flatMap(it -> ((ComponentModifiers) it).getList().stream());
+ }
+
+ static boolean isInteresting(Component component) {
+ boolean interesting =
+ isContainerWithSemantics(component)
+ || modifiersStream(component)
+ .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics);
+
+ return interesting && component.isVisible();
+ }
+
+ static boolean isModifierWithSemantics(ModifierOperation modifier) {
+ return modifier instanceof AccessibilitySemantics
+ && ((AccessibilitySemantics) modifier).isInterestingForSemantics();
+ }
+
+ static boolean isContainerWithSemantics(Component component) {
+ if (component instanceof AccessibilitySemantics) {
+ return ((AccessibilitySemantics) component).isInterestingForSemantics();
+ }
+
+ if (!(component instanceof LayoutComponent)) {
+ return false;
+ }
+
+ return ((LayoutComponent) component)
+ .getComponentModifiers().getList().stream()
+ .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java
new file mode 100644
index 0000000..c9ad28a
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java
@@ -0,0 +1,163 @@
+/*
+ * 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.accessibility;
+
+import static com.android.internal.widget.remotecompose.accessibility.RemoteComposeDocumentAccessibility.RootId;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.util.IntArray;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.widget.ExploreByTouchHelper;
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics.Mode;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+public class PlatformRemoteComposeTouchHelper<N, C, S> extends ExploreByTouchHelper {
+ private final RemoteComposeDocumentAccessibility<C, S> mRemoteDocA11y;
+
+ private final SemanticNodeApplier<AccessibilityNodeInfo, C, S> mApplier;
+
+ public PlatformRemoteComposeTouchHelper(
+ View host,
+ RemoteComposeDocumentAccessibility<C, S> remoteDocA11y,
+ SemanticNodeApplier<AccessibilityNodeInfo, C, S> applier) {
+ super(host);
+ this.mRemoteDocA11y = remoteDocA11y;
+ this.mApplier = applier;
+ }
+
+ public static PlatformRemoteComposeTouchHelper<
+ AccessibilityNodeInfo, Component, AccessibilitySemantics>
+ forRemoteComposePlayer(View player, @NonNull CoreDocument coreDocument) {
+ return new PlatformRemoteComposeTouchHelper<>(
+ player,
+ new CoreDocumentAccessibility(coreDocument),
+ new AndroidPlatformSemanticNodeApplier());
+ }
+
+ /**
+ * Gets the virtual view ID at a given location on the screen.
+ *
+ * <p>This method is called by the Accessibility framework to determine which virtual view, if
+ * any, is located at a specific point on the screen. It uses the {@link
+ * RemoteComposeDocumentAccessibility#getComponentIdAt(PointF)} method to find the ID of the
+ * component at the given coordinates.
+ *
+ * @param x The x-coordinate of the location in pixels.
+ * @param y The y-coordinate of the location in pixels.
+ * @return The ID of the virtual view at the given location, or {@link #INVALID_ID} if no
+ * virtual view is found at that location.
+ */
+ @Override
+ protected int getVirtualViewAt(float x, float y) {
+ Integer root = mRemoteDocA11y.getComponentIdAt(new PointF(x, y));
+
+ if (root == null) {
+ return INVALID_ID;
+ }
+
+ return root;
+ }
+
+ /**
+ * Populates a list with the visible virtual view IDs.
+ *
+ * <p>This method is called by the accessibility framework to retrieve the IDs of all visible
+ * virtual views in the accessibility hierarchy. It traverses the hierarchy starting from the
+ * root node (RootId) and adds the ID of each visible view to the provided list.
+ *
+ * @param virtualViewIds The list to be populated with the visible virtual view IDs.
+ */
+ @Override
+ protected void getVisibleVirtualViews(IntArray virtualViewIds) {
+ Stack<Integer> toVisit = new Stack<>();
+ Set<Integer> visited = new HashSet<>();
+
+ toVisit.push(RootId);
+
+ while (!toVisit.isEmpty()) {
+ Integer componentId = toVisit.remove(0);
+
+ if (visited.add(componentId)) {
+ virtualViewIds.add(componentId);
+
+ C component = mRemoteDocA11y.findComponentById(componentId);
+
+ if (component != null) {
+ boolean allSet =
+ mRemoteDocA11y.mergeMode(component).stream()
+ .allMatch(i -> i == Mode.SET);
+
+ if (allSet) {
+ List<Integer> childViews =
+ mRemoteDocA11y.semanticallyRelevantChildComponents(component);
+
+ toVisit.addAll(childViews);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onPopulateNodeForVirtualView(
+ int virtualViewId, @NonNull AccessibilityNodeInfo node) {
+ C component = mRemoteDocA11y.findComponentById(virtualViewId);
+
+ List<Mode> mode = mRemoteDocA11y.mergeMode(component);
+
+ if (mode.contains(Mode.MERGE)) {
+ List<Integer> childViews =
+ mRemoteDocA11y.semanticallyRelevantChildComponents(component);
+
+ for (Integer childView : childViews) {
+ onPopulateNodeForVirtualView(childView, node);
+ }
+ }
+
+ List<S> semantics = mRemoteDocA11y.semanticModifiersForComponent(component);
+ mApplier.applyComponent(mRemoteDocA11y, node, component, semantics);
+ }
+
+ @Override
+ protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ // TODO
+ }
+
+ @Override
+ protected boolean onPerformActionForVirtualView(
+ int virtualViewId, int action, @Nullable Bundle arguments) {
+ C component = mRemoteDocA11y.findComponentById(virtualViewId);
+
+ if (component != null) {
+ return mRemoteDocA11y.performAction(component, action, arguments);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java
new file mode 100644
index 0000000..14977be
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java
@@ -0,0 +1,100 @@
+/*
+ * 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.accessibility;
+
+import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
+
+import java.util.List;
+
+/**
+ * Interface for interacting with the accessibility features of a remote Compose UI. This interface
+ * provides methods to perform actions, retrieve state, and query the accessibility tree of the
+ * remote Compose UI.
+ *
+ * @param <C> The type of component in the remote Compose UI.
+ * @param <S> The type representing semantic modifiers applied to components.
+ */
+public interface RemoteComposeDocumentAccessibility<C, S> {
+ // Matches ExploreByTouchHelper.HOST_ID
+ Integer RootId = View.NO_ID;
+
+ // androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK
+ int ACTION_CLICK = 0x00000010;
+
+ /**
+ * Performs the specified action on the given component.
+ *
+ * @param component The component on which to perform the action.
+ * @param action The action to perform.
+ * @param arguments Optional arguments for the action.
+ * @return {@code true} if the action was performed successfully, {@code false} otherwise.
+ */
+ boolean performAction(C component, int action, Bundle arguments);
+
+ /**
+ * Retrieves the string value associated with the given ID.
+ *
+ * @param id The ID to retrieve the string value for.
+ * @return The string value associated with the ID, or {@code null} if no such value exists.
+ */
+ @Nullable
+ String stringValue(int id);
+
+ /**
+ * Retrieves a list of child view IDs semantically contained within the given component/virtual
+ * view. These may later be hidden from accessibility services by properties, but should contain
+ * only possibly semantically relevant virtual views.
+ *
+ * @param component The component to retrieve child view IDs from, or [RootId] for the top
+ * level.
+ * @return A list of integer IDs representing the child views of the component.
+ */
+ List<Integer> semanticallyRelevantChildComponents(C component);
+
+ /**
+ * Retrieves the semantic modifiers associated with a given component.
+ *
+ * @param component The component for which to retrieve semantic modifiers.
+ * @return A list of semantic modifiers applicable to the component.
+ */
+ List<S> semanticModifiersForComponent(C component);
+
+ /**
+ * Gets all applied merge modes of the given component. A Merge mode is one of Set, Merge or
+ * Clear and describes how to apply and combine hierarchical semantics.
+ *
+ * @param component The component to merge the mode for.
+ * @return A list of merged modes, potentially conflicting but to be resolved by the caller.
+ */
+ List<CoreSemantics.Mode> mergeMode(C component);
+
+ /**
+ * Finds a component by its ID.
+ *
+ * @param id the ID of the component to find
+ * @return the component with the given ID, or {@code null} if no such component exists
+ */
+ @Nullable
+ C findComponentById(int id);
+
+ @Nullable
+ Integer getComponentIdAt(PointF point);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java
new file mode 100644
index 0000000..4ff7892
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java
@@ -0,0 +1,31 @@
+/*
+ * 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.accessibility;
+
+import android.annotation.NonNull;
+import android.view.View;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+
+public class RemoteComposeTouchHelper {
+ public static View.AccessibilityDelegate forRemoteComposePlayer(
+ View player, @NonNull CoreDocument coreDocument) {
+ return new PlatformRemoteComposeTouchHelper<>(
+ player,
+ new CoreDocumentAccessibility(coreDocument),
+ new AndroidPlatformSemanticNodeApplier());
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java
new file mode 100644
index 0000000..4368329
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java
@@ -0,0 +1,43 @@
+/*
+ * 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.accessibility;
+
+import java.util.List;
+
+/**
+ * An interface for applying semantic information to a semantics node.
+ *
+ * <p>Implementations of this interface are responsible for taking a node represented by [nodeInfo]
+ * and applying a list of [semantics] (representing accessible actions and properties) to it. This
+ * process might involve: - Modifying the node's properties (e.g., content description, clickable
+ * state). - Adding a child node to represent a specific semantic element. - Performing any other
+ * action necessary to make the node semantically meaningful and accessible to assistive
+ * technologies.
+ *
+ * @param <N> The type representing information about the node. This could be an Androidx
+ * `AccessibilityNodeInfoCompat`, or potentially a platform `AccessibilityNodeInfo`.
+ * @param <C> The type of component in the remote Compose UI.
+ * @param <S> The type representing a single semantic property or action.
+ */
+public interface SemanticNodeApplier<N, C, S> {
+ void applyComponent(
+ RemoteComposeDocumentAccessibility<C, S> remoteComposeAccessibility,
+ N nodeInfo,
+ C component,
+ List<S> semantics);
+
+ String VIRTUAL_VIEW_ID_KEY = "VirtualViewId";
+}
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 370289a..5bc3bca 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.IntegerExpression;
@@ -28,7 +29,6 @@
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.LoopEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd;
@@ -38,6 +38,7 @@
import com.android.internal.widget.remotecompose.core.operations.layout.TouchUpModifierOperation;
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.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.ArrayList;
@@ -53,13 +54,14 @@
public class CoreDocument {
private static final boolean DEBUG = false;
+ private static final int DOCUMENT_API_LEVEL = 2;
@NonNull ArrayList<Operation> mOperations = new ArrayList<>();
@Nullable RootLayoutComponent mRootLayoutComponent = null;
@NonNull RemoteComposeState mRemoteComposeState = new RemoteComposeState();
- @NonNull TimeVariables mTimeVariables = new TimeVariables();
+ @VisibleForTesting @NonNull public TimeVariables mTimeVariables = new TimeVariables();
// Semantic version of the document
@NonNull Version mVersion = new Version(0, 1, 0);
@@ -86,6 +88,11 @@
private int mLastId = 1; // last component id when inflating the file
+ /** Returns a version number that is monotonically increasing. */
+ public static int getDocumentApiLevel() {
+ return DOCUMENT_API_LEVEL;
+ }
+
@Nullable
public String getContentDescription() {
return mContentDescription;
@@ -565,6 +572,7 @@
TouchUpModifierOperation currentTouchUpModifier = null;
TouchCancelModifierOperation currentTouchCancelModifier = null;
LoopOperation currentLoop = null;
+ ScrollModifierOperation currentScrollModifier = null;
mLastId = -1;
for (Operation o : operations) {
@@ -579,8 +587,8 @@
mLastId = component.getComponentId();
}
} else if (o instanceof ComponentEnd) {
- if (currentComponent instanceof LayoutComponent) {
- ((LayoutComponent) currentComponent).inflate();
+ if (currentComponent != null) {
+ currentComponent.inflate();
}
components.remove(components.size() - 1);
if (!components.isEmpty()) {
@@ -602,6 +610,9 @@
} else if (o instanceof TouchCancelModifierOperation) {
currentTouchCancelModifier = (TouchCancelModifierOperation) o;
ops = currentTouchCancelModifier.getList();
+ } else if (o instanceof ScrollModifierOperation) {
+ currentScrollModifier = (ScrollModifierOperation) o;
+ ops = currentScrollModifier.getList();
} else if (o instanceof OperationsListEnd) {
ops = currentComponent.getList();
if (currentClickModifier != null) {
@@ -616,6 +627,9 @@
} else if (currentTouchCancelModifier != null) {
ops.add(currentTouchCancelModifier);
currentTouchCancelModifier = null;
+ } else if (currentScrollModifier != null) {
+ ops.add(currentScrollModifier);
+ currentScrollModifier = null;
}
} else if (o instanceof LoopOperation) {
currentLoop = (LoopOperation) o;
@@ -881,7 +895,7 @@
}
if (mRootLayoutComponent != null) {
for (Component component : mAppliedTouchOperations) {
- component.onTouchUp(context, this, x, y, true);
+ component.onTouchUp(context, this, x, y, dx, dy, true);
}
mAppliedTouchOperations.clear();
}
@@ -1039,7 +1053,13 @@
|| context.getTheme() == Theme.UNSPECIFIED;
}
if (apply) {
- op.apply(context);
+ if (op.isDirty() || op instanceof PaintOperation) {
+ if (op.isDirty() && op instanceof VariableSupport) {
+ op.markNotDirty();
+ ((VariableSupport) op).updateVariables(context);
+ }
+ op.apply(context);
+ }
}
}
if (context.getPaintContext().doesNeedsRepaint()
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operation.java b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
index 6f6a0a8..150ebd0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operation.java
@@ -20,6 +20,8 @@
/** Base interface for RemoteCompose operations */
public abstract class Operation {
+ private static final boolean ENABLE_DIRTY_FLAG_OPTIMIZATION = true;
+
/** add the operation to the buffer */
public abstract void write(@NonNull WireBuffer buffer);
@@ -33,4 +35,30 @@
/** Debug utility to display an operation + indentation */
@NonNull
public abstract String deepToString(@NonNull String indent);
+
+ private boolean mDirty = true;
+
+ /** Mark the operation as "dirty" to indicate it will need to be re-executed. */
+ public void markDirty() {
+ mDirty = true;
+ }
+
+ /** Mark the operation as "not dirty" */
+ public void markNotDirty() {
+ if (ENABLE_DIRTY_FLAG_OPTIMIZATION) {
+ mDirty = false;
+ }
+ }
+
+ /**
+ * Returns true if the operation is marked as "dirty"
+ *
+ * @return true if dirty
+ */
+ public boolean isDirty() {
+ if (ENABLE_DIRTY_FLAG_OPTIMIZATION) {
+ return mDirty;
+ }
+ return true;
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java
index 741303a..06beffc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/OperationInterface.java
@@ -33,4 +33,14 @@
/** Debug utility to display an operation + indentation */
@NonNull
String deepToString(@NonNull String indent);
+
+ /**
+ * Returns true if the operation is marked as "dirty"
+ *
+ * @return true if dirty
+ */
+ boolean isDirty();
+
+ /** Mark the operation as "dirty" to indicate it will need to be re-executed. */
+ void markNotDirty();
}
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 006fe3a..04e490f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -98,8 +98,10 @@
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostActionOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HostNamedActionOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.MarqueeModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ValueFloatChangeActionOperation;
@@ -110,6 +112,7 @@
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
import com.android.internal.widget.remotecompose.core.types.BooleanConstant;
import com.android.internal.widget.remotecompose.core.types.IntegerConstant;
import com.android.internal.widget.remotecompose.core.types.LongConstant;
@@ -126,6 +129,9 @@
public static final int CLICK_AREA = 64;
public static final int ROOT_CONTENT_BEHAVIOR = 65;
public static final int ROOT_CONTENT_DESCRIPTION = 103;
+ // TODO reorder before submitting
+ public static final int ACCESSIBILITY_SEMANTICS = 250;
+ // public static final int ACCESSIBILITY_CUSTOM_ACTION = 251;
////////////////////////////////////////
// Draw commands
@@ -223,6 +229,8 @@
public static final int MODIFIER_ZINDEX = 223;
public static final int MODIFIER_GRAPHICS_LAYER = 224;
public static final int MODIFIER_SCROLL = 226;
+ public static final int MODIFIER_MARQUEE = 228;
+ public static final int MODIFIER_RIPPLE = 229;
public static final int LOOP_START = 215;
public static final int LOOP_END = 216;
@@ -327,6 +335,8 @@
map.put(MODIFIER_ZINDEX, ZIndexModifierOperation::read);
map.put(MODIFIER_GRAPHICS_LAYER, GraphicsLayerModifierOperation::read);
map.put(MODIFIER_SCROLL, ScrollModifierOperation::read);
+ map.put(MODIFIER_MARQUEE, MarqueeModifierOperation::read);
+ map.put(MODIFIER_RIPPLE, RippleModifierOperation::read);
map.put(OPERATIONS_LIST_END, OperationsListEnd::read);
@@ -362,5 +372,8 @@
map.put(PATH_TWEEN, PathTween::read);
map.put(PATH_CREATE, PathCreate::read);
map.put(PATH_ADD, PathAppend::read);
+
+ map.put(ACCESSIBILITY_SEMANTICS, CoreSemantics::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 3a5d68d..0ae7a94 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -15,7 +15,6 @@
*/
package com.android.internal.widget.remotecompose.core;
-import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.ADD;
import static com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression.MUL;
import android.annotation.NonNull;
@@ -81,6 +80,7 @@
import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponentContent;
import com.android.internal.widget.remotecompose.core.operations.layout.LoopEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.LoopOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.OperationsListEnd;
import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.BoxLayout;
import com.android.internal.widget.remotecompose.core.operations.layout.managers.CanvasLayout;
@@ -92,8 +92,10 @@
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.BorderModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ClipRectModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.GraphicsLayerModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.MarqueeModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.OffsetModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RippleModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.RoundedClipRectModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation;
@@ -1610,7 +1612,7 @@
* create and animation based on description and return as an array of floats. see
* addAnimatedFloat
*
- * @param duration the duration of the aimation
+ * @param duration the duration of the animation in seconds
* @param type the type of animation
* @param spec the parameters of the animation if any
* @param initialValue the initial value if it animates to a start
@@ -1699,6 +1701,9 @@
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,
@@ -1707,20 +1712,13 @@
0f,
3,
new float[] {
- touchExpressionDirection,
- -1,
- // TODO: remove this CONTINUOUS_SEC hack...
- MUL,
- RemoteContext.FLOAT_CONTINUOUS_SEC,
- 0f,
- MUL,
- ADD
+ touchExpressionDirection, -1, MUL,
},
TouchExpression.STOP_NOTCHES_EVEN,
new float[] {notches, notchMax},
null);
- ScrollModifierOperation.apply(mBuffer, direction, positionId, max, notchMax);
+ OperationsListEnd.apply(mBuffer);
}
/**
@@ -1786,6 +1784,38 @@
ZIndexModifierOperation.apply(mBuffer, value);
}
+ /** Add a ripple effect on touch down as a modifier */
+ public void addModifierRipple() {
+ RippleModifierOperation.apply(mBuffer);
+ }
+
+ /**
+ * Add a marquee modifier
+ *
+ * @param iterations
+ * @param animationMode
+ * @param repeatDelayMillis
+ * @param initialDelayMillis
+ * @param spacing
+ * @param velocity
+ */
+ public void addModifierMarquee(
+ int iterations,
+ int animationMode,
+ float repeatDelayMillis,
+ float initialDelayMillis,
+ float spacing,
+ float velocity) {
+ MarqueeModifierOperation.apply(
+ mBuffer,
+ iterations,
+ animationMode,
+ repeatDelayMillis,
+ initialDelayMillis,
+ spacing,
+ velocity);
+ }
+
/**
* Add a graphics layer
*
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index f5f9e21..11e58ba 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -48,6 +48,10 @@
private final IntMap<DataMap> mDataMapMap = new IntMap<>();
private final IntMap<Object> mObjectMap = new IntMap<>();
+ // path information
+ private final IntMap<Object> mPathMap = new IntMap<>();
+ private final IntMap<float[]> mPathData = new IntMap<>();
+
private final boolean[] mColorOverride = new boolean[MAX_COLORS];
@NonNull private final IntMap<ArrayAccess> mCollectionMap = new IntMap<>();
@@ -131,12 +135,44 @@
}
}
- private final IntMap<float[]> mPathData = new IntMap<>();
-
- public void putPathData(int id, float[] data) {
- mPathData.put(id, data);
+ /**
+ * Get the path asociated with the Data
+ *
+ * @param id
+ * @return
+ */
+ public Object getPath(int id) {
+ return mPathMap.get(id);
}
+ /**
+ * Cache a path object. Object will be cleared if you update path data.
+ *
+ * @param id number asociated with path
+ * @param path the path object typically Android Path
+ */
+ public void putPath(int id, Object path) {
+ mPathMap.put(id, path);
+ }
+
+ /**
+ * The path data the Array of floats that is asoicated with the path It also removes the current
+ * path object.
+ *
+ * @param id the integer asociated with the data and path
+ * @param data the array of floats that represents the path
+ */
+ public void putPathData(int id, float[] data) {
+ mPathData.put(id, data);
+ mPathMap.remove(id);
+ }
+
+ /**
+ * Get the path data asociated with the id
+ *
+ * @param id number that represents the path
+ * @return path data
+ */
public float[] getPathData(int id) {
return mPathData.get(id);
}
@@ -283,7 +319,7 @@
ArrayList<VariableSupport> v = mVarListeners.get(id);
if (v != null && mRemoteContext != null) {
for (VariableSupport c : v) {
- c.updateVariables(mRemoteContext);
+ c.markDirty();
}
}
}
@@ -426,9 +462,6 @@
* @return
*/
public int getOpsToUpdate(@NonNull RemoteContext context) {
- for (VariableSupport vs : mAllVarListeners) {
- vs.updateVariables(context);
- }
if (mVarListeners.get(RemoteContext.ID_CONTINUOUS_SEC) != null) {
return 1;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 6eb8463..003acb7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -214,6 +214,13 @@
*/
public abstract void hapticEffect(int type);
+ /** Set the repaint flag. This will trigger a repaint of the current document. */
+ public void needsRepaint() {
+ if (mPaintContext != null) {
+ mPaintContext.needsRepaint();
+ }
+ }
+
/**
* The context can be used in a few different mode, allowing operations to skip being executed:
* - UNSET : all operations will get executed - DATA : only operations dealing with DATA (eg
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
index 14aed2f..0ed6005 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
@@ -29,9 +29,7 @@
*
* @param context
*/
- public void updateTime(@NonNull RemoteContext context) {
- LocalDateTime dateTime =
- LocalDateTime.now(ZoneId.systemDefault()); // TODO, pass in a timezone explicitly?
+ public void updateTime(@NonNull RemoteContext context, ZoneId zoneId, LocalDateTime dateTime) {
// This define the time in the format
// seconds run from Midnight=0 quantized to seconds hour 0..3599
// minutes run from Midnight=0 quantized to minutes 0..1439
@@ -48,8 +46,7 @@
float sec = currentSeconds + dateTime.getNano() * 1E-9f;
int day_week = dateTime.getDayOfWeek().getValue();
- ZoneId zone = ZoneId.systemDefault();
- OffsetDateTime offsetDateTime = dateTime.atZone(zone).toOffsetDateTime();
+ OffsetDateTime offsetDateTime = dateTime.atZone(zoneId).toOffsetDateTime();
ZoneOffset offset = offsetDateTime.getOffset();
context.loadFloat(RemoteContext.ID_OFFSET_TO_UTC, offset.getTotalSeconds());
@@ -61,4 +58,16 @@
context.loadFloat(RemoteContext.ID_DAY_OF_MONTH, month);
context.loadFloat(RemoteContext.ID_WEEK_DAY, day_week);
}
+
+ /**
+ * This class populates all time variables in the system
+ *
+ * @param context
+ */
+ public void updateTime(@NonNull RemoteContext context) {
+ ZoneId zone = ZoneId.systemDefault();
+ LocalDateTime dateTime = LocalDateTime.now(zone);
+
+ updateTime(context, zone, dateTime);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java
index 3dda678..611ba97 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/TouchListener.java
@@ -15,10 +15,34 @@
*/
package com.android.internal.widget.remotecompose.core;
+/** Interface used by objects to register for touch events */
public interface TouchListener {
+ /**
+ * Called when touch down happens
+ *
+ * @param context The players context
+ * @param x the x location of the down touch
+ * @param y the y location of the down touch
+ */
void touchDown(RemoteContext context, float x, float y);
+ /**
+ * called on touch up
+ *
+ * @param context the players context
+ * @param x the x location
+ * @param y the y location
+ * @param dx the x velocity when the touch up happened
+ * @param dy the y valocity when the touch up happened
+ */
void touchUp(RemoteContext context, float x, float y, float dx, float dy);
+ /**
+ * Drag event (occur between down and up)
+ *
+ * @param context the players context
+ * @param x the x coord of the drag
+ * @param y the y coord of the drag
+ */
void touchDrag(RemoteContext context, float x, float y);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
index e9fa897..1f3e290 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
@@ -36,4 +36,7 @@
* @param context
*/
void updateVariables(@NonNull RemoteContext context);
+
+ /** Mark the operation as dirty to indicate that the variables it references are out of date. */
+ void markDirty();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 27ba652..784897b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -45,15 +45,39 @@
short mType;
short mEncoding;
@NonNull final byte[] mBitmap;
+
+ /** The max size of width or height */
public static final int MAX_IMAGE_DIMENSION = 8000;
+
+ /** The data is encoded in the file (default) */
public static final short ENCODING_INLINE = 0;
+
+ /** The data is encoded in the url */
public static final short ENCODING_URL = 1;
+
+ /** The data is encoded as a reference to file */
public static final short ENCODING_FILE = 2;
+
+ /** The data is encoded as PNG_8888 (default) */
public static final short TYPE_PNG_8888 = 0;
+
+ /** The data is encoded as PNG */
public static final short TYPE_PNG = 1;
+
+ /** The data is encoded as RAW 8 bit */
public static final short TYPE_RAW8 = 2;
+
+ /** The data is encoded as RAW 8888 bit */
public static final short TYPE_RAW8888 = 3;
+ /**
+ * create a bitmap structure
+ *
+ * @param imageId the id to store the image
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param bitmap the data
+ */
public BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap) {
this.mImageId = imageId;
this.mImageWidth = width;
@@ -61,10 +85,20 @@
this.mBitmap = bitmap;
}
+ /**
+ * The width of the image
+ *
+ * @return the width
+ */
public int getWidth() {
return mImageWidth;
}
+ /**
+ * The height of the image
+ *
+ * @return the height
+ */
public int getHeight() {
return mImageHeight;
}
@@ -80,6 +114,11 @@
return "BITMAP DATA " + mImageId;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -94,6 +133,15 @@
return OP_CODE;
}
+ /**
+ * Add the image to the document
+ *
+ * @param buffer document to write to
+ * @param imageId the id the image will be stored under
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param bitmap the data used to store/encode the image
+ */
public static void apply(
@NonNull WireBuffer buffer,
int imageId,
@@ -107,6 +155,17 @@
buffer.writeBuffer(bitmap);
}
+ /**
+ * Add the image to the document (using the ehanced encoding)
+ *
+ * @param buffer document to write to
+ * @param imageId the id the image will be stored under
+ * @param type the type of image
+ * @param width the width of the image
+ * @param encoding the encoding
+ * @param height the height of the image
+ * @param bitmap the data used to store/encode the image
+ */
public static void apply(
@NonNull WireBuffer buffer,
int imageId,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
index 5e5e565..efd31af 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
@@ -24,11 +24,12 @@
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 com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
import java.util.List;
/** Add a click area to the document */
-public class ClickArea extends Operation implements RemoteComposeOperation {
+public class ClickArea extends Operation implements RemoteComposeOperation, AccessibleComponent {
private static final int OP_CODE = Operations.CLICK_AREA;
private static final String CLASS_NAME = "ClickArea";
int mId;
@@ -113,6 +114,11 @@
return indent + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -127,6 +133,21 @@
return OP_CODE;
}
+ @Override
+ public Integer getContentDescriptionId() {
+ return mContentDescription;
+ }
+
+ /**
+ * @param buffer
+ * @param id
+ * @param contentDescription
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ * @param metadata
+ */
public static void apply(
@NonNull WireBuffer buffer,
int id,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index 2fe56d3..b55f25c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -83,6 +83,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index defa656..5a495d5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -28,8 +28,8 @@
/** Support clip with a rectangle */
public class ClipRect extends DrawBase4 {
- public static final int OP_CODE = Operations.CLIP_RECT;
- public static final String CLASS_NAME = "ClipRect";
+ private static final int OP_CODE = Operations.CLIP_RECT;
+ private static final String CLASS_NAME = "ClipRect";
/**
* Read this operation and add it to the list of operations
@@ -51,6 +51,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
index d86576d..6802015 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorConstant.java
@@ -61,6 +61,11 @@
return "ColorConstant[" + mColorId + "] = " + Utils.colorInt(mColor) + "";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
index 66f128f..b385ecd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -199,6 +199,11 @@
+ ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
index 19c219b..3e85236 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ComponentValue.java
@@ -31,8 +31,8 @@
import java.util.List;
public class ComponentValue extends Operation implements SerializableToString {
- public static final int OP_CODE = Operations.COMPONENT_VALUE;
- public static final String CLASS_NAME = "ComponentValue";
+ private static final int OP_CODE = Operations.COMPONENT_VALUE;
+ private static final String CLASS_NAME = "ComponentValue";
public static final int WIDTH = 0;
public static final int HEIGHT = 1;
@@ -50,6 +50,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
index e888074..ff85721 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DataMapIds.java
@@ -129,6 +129,11 @@
operations.add(data);
}
+ /**
+ * 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("Data Operations", OP_CODE, CLASS_NAME)
.description("Encode a collection of name id pairs")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index 3f95f02..fd1f410 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -26,8 +26,9 @@
import java.util.List;
+/** Draw an Arc command the specified arc, will be scaled to fit inside the specified oval. */
public class DrawArc extends DrawBase6 {
- public static final int OP_CODE = Operations.DRAW_ARC;
+ private static final int OP_CODE = Operations.DRAW_ARC;
private static final String CLASS_NAME = "DrawArc";
/**
@@ -114,8 +115,20 @@
"Sweep angle (in degrees) measured clockwise");
}
- public DrawArc(float v1, float v2, float v3, float v4, float v5, float v6) {
- super(v1, v2, v3, v4, v5, v6);
+ /**
+ * Create Draw Arc command Draw the specified arc, which will be scaled to fit inside the
+ * specified oval.
+ *
+ * @param left the left side of the oval
+ * @param top the top of the oval
+ * @param right the right side of the oval
+ * @param bottom the bottom of the oval
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public DrawArc(
+ float left, float top, float right, float bottom, float startAngle, float sweepAngle) {
+ super(left, top, right, bottom, startAngle, sweepAngle);
mName = "DrawArc";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
index 6c288a35..64c2730 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
@@ -145,6 +145,11 @@
return null;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "DrawBase6";
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index 69f5cc5..cdb527d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -118,6 +118,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
index 66646d7..638fe14 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java
@@ -24,11 +24,12 @@
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 com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
import java.util.List;
/** Operation to draw a given cached bitmap */
-public class DrawBitmapInt extends PaintOperation {
+public class DrawBitmapInt extends PaintOperation implements AccessibleComponent {
private static final int OP_CODE = Operations.DRAW_BITMAP_INT;
private static final String CLASS_NAME = "DrawBitmapInt";
int mImageId;
@@ -106,6 +107,16 @@
+ ";";
}
+ @Override
+ public Integer getContentDescriptionId() {
+ return mContentDescId;
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -170,6 +181,11 @@
operations.add(op);
}
+ /**
+ * 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("Draw Operations", OP_CODE, CLASS_NAME)
.description("Draw a bitmap using integer coordinates")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
index 1701486..d6467c9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapScaled.java
@@ -27,11 +27,13 @@
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
import com.android.internal.widget.remotecompose.core.operations.utilities.ImageScaling;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
import java.util.List;
/** Operation to draw a given cached bitmap */
-public class DrawBitmapScaled extends PaintOperation implements VariableSupport {
+public class DrawBitmapScaled extends PaintOperation
+ implements VariableSupport, AccessibleComponent {
private static final int OP_CODE = Operations.DRAW_BITMAP_SCALED;
private static final String CLASS_NAME = "DrawBitmapScaled";
int mImageId;
@@ -191,6 +193,16 @@
+ Utils.floatToString(mScaleFactor, mOutScaleFactor);
}
+ @Override
+ public Integer getContentDescriptionId() {
+ return mContentDescId;
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index e6aecdb..735e262 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -50,6 +50,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index 04f3264..f3a190d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -52,6 +52,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index 0a50042..a009874 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -50,6 +50,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index 41b8243..398cf48 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -62,6 +62,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index 7e22550..38477ad 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -51,6 +51,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
index 7616df0..51ece77 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawSector.java
@@ -27,7 +27,7 @@
import java.util.List;
public class DrawSector extends DrawBase6 {
- public static final int OP_CODE = Operations.DRAW_SECTOR;
+ private static final int OP_CODE = Operations.DRAW_SECTOR;
private static final String CLASS_NAME = "DrawSector";
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
index 2c5d790..8adba1d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
@@ -121,6 +121,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
index 7de52b8..f839922 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -130,6 +130,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index 18d9fdf..86f3c99 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -98,6 +98,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "DrawTextOnPath";
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index b83e4c2..d4d4a5e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -108,6 +108,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "DrawTweenPath";
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
index 7dd435a..e04e691 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -51,6 +51,11 @@
return "FloatConstant[" + mTextId + "] = " + mValue;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
index 3d92e12..c1872fd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -139,6 +139,11 @@
}
}
+ // Keep track of the last computed value when we are animated,
+ // e.g. if FloatAnimation or Spring is used, so that we can
+ // ask for a repaint.
+ float mLastAnimatedValue = Float.NaN;
+
@Override
public void apply(@NonNull RemoteContext context) {
updateVariables(context);
@@ -146,12 +151,23 @@
if (Float.isNaN(mLastChange)) {
mLastChange = t;
}
+ float lastComputedValue;
if (mFloatAnimation != null && !Float.isNaN(mLastCalculatedValue)) {
float f = mFloatAnimation.get(t - mLastChange);
context.loadFloat(mId, f);
+ lastComputedValue = f;
+ if (lastComputedValue != mLastAnimatedValue) {
+ mLastAnimatedValue = lastComputedValue;
+ context.needsRepaint();
+ }
} else if (mSpring != null) {
float f = mSpring.get(t - mLastChange);
context.loadFloat(mId, f);
+ lastComputedValue = f;
+ if (lastComputedValue != mLastAnimatedValue) {
+ mLastAnimatedValue = lastComputedValue;
+ context.needsRepaint();
+ }
} else {
float v =
mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
@@ -205,6 +221,11 @@
+ ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -236,6 +257,9 @@
buffer.writeInt(id);
int len = value.length;
+ if (len > MAX_EXPRESSION_SIZE) {
+ throw new RuntimeException(AnimatedFloatExpression.toString(value, null) + " to long");
+ }
if (animation != null) {
len |= (animation.length << 16);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
index 04e4346..656dc09 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java
@@ -39,7 +39,7 @@
private static final int OP_CODE = Operations.HEADER;
private static final String CLASS_NAME = "Header";
public static final int MAJOR_VERSION = 0;
- public static final int MINOR_VERSION = 1;
+ public static final int MINOR_VERSION = 2;
public static final int PATCH_VERSION = 0;
int mMajorVersion;
@@ -115,6 +115,11 @@
return toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
index 67274af..f04f30d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/IntegerExpression.java
@@ -136,6 +136,11 @@
return "IntegerExpression[" + mId + "] = (" + s + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index aed597a..044430d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -26,6 +26,7 @@
import java.util.List;
+/** The restore previous matrix command */
public class MatrixRestore extends PaintOperation {
private static final int OP_CODE = Operations.MATRIX_RESTORE;
private static final String CLASS_NAME = "MatrixRestore";
@@ -54,6 +55,11 @@
return "MatrixRestore";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index fece143..57f5a0e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -26,8 +26,9 @@
import java.util.List;
+/** The rotate the rendering command */
public class MatrixRotate extends DrawBase3 {
- public static final int OP_CODE = Operations.MATRIX_ROTATE;
+ private static final int OP_CODE = Operations.MATRIX_ROTATE;
private static final String CLASS_NAME = "MatrixRotate";
/**
@@ -57,6 +58,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
index 7eb7b3f..aec316a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java
@@ -26,6 +26,7 @@
import java.util.List;
+/** The save the matrix state command */
public class MatrixSave extends PaintOperation {
private static final int OP_CODE = Operations.MATRIX_SAVE;
private static final String CLASS_NAME = "MatrixSave";
@@ -52,6 +53,11 @@
operations.add(op);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index 49bdd1b..07f965f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -26,9 +26,10 @@
import java.util.List;
+/** Scale the rendering matrix command */
public class MatrixScale extends DrawBase4 {
- public static final int OP_CODE = Operations.MATRIX_SCALE;
- public static final String CLASS_NAME = "MatrixScale";
+ private static final int OP_CODE = Operations.MATRIX_SCALE;
+ private static final String CLASS_NAME = "MatrixScale";
/**
* Read this operation and add it to the list of operations
@@ -50,6 +51,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
index 54b6fd1..b31492d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java
@@ -27,9 +27,10 @@
import java.util.List;
+/** Skew the matrix command */
public class MatrixSkew extends DrawBase2 {
- public static final int OP_CODE = Operations.MATRIX_SKEW;
- public static final String CLASS_NAME = "MatrixSkew";
+ private static final int OP_CODE = Operations.MATRIX_SKEW;
+ private static final String CLASS_NAME = "MatrixSkew";
/**
* Read this operation and add it to the list of operations
@@ -51,6 +52,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index b57d83b..11fa040 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -26,9 +26,10 @@
import java.util.List;
+/** translate the matrix command */
public class MatrixTranslate extends DrawBase2 {
- public static final int OP_CODE = Operations.MATRIX_TRANSLATE;
- public static final String CLASS_NAME = "MatrixTranslate";
+ private static final int OP_CODE = Operations.MATRIX_TRANSLATE;
+ private static final String CLASS_NAME = "MatrixTranslate";
/**
* Read this operation and add it to the list of operations
@@ -50,6 +51,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
index 3c82f2b..dde632e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -64,6 +64,11 @@
+ mVarType;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index 3c0a842..daf2c55 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -61,6 +61,11 @@
return "PaintData " + "\"" + mPaintData + "\"";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -92,6 +97,11 @@
operations.add(data);
}
+ /**
+ * 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("Data Operations", OP_CODE, CLASS_NAME)
.description("Encode a Paint ")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
index 2b00001..7ff879e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathAppend.java
@@ -109,6 +109,11 @@
public static final float CLOSE_NAN = Utils.asNan(CLOSE);
public static final float DONE_NAN = Utils.asNan(DONE);
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -162,11 +167,12 @@
}
@Override
- public void paint(PaintContext context) {}
+ public void paint(PaintContext context) {
+ apply(context.getContext());
+ }
@Override
public void apply(@NonNull RemoteContext context) {
- updateVariables(context);
float[] data = context.getPathData(mInstanceId);
float[] out = mOutputPath;
if (data != null) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
index b62f36b..75562cd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathCreate.java
@@ -48,6 +48,7 @@
@Override
public void updateVariables(@NonNull RemoteContext context) {
+
for (int i = 0; i < mFloatPath.length; i++) {
float v = mFloatPath[i];
if (Utils.isVariable(v)) {
@@ -81,7 +82,19 @@
@NonNull
@Override
public String toString() {
- return "PathCreate[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\"";
+ return "PathCreate["
+ + mInstanceId
+ + "] = "
+ + "\""
+ + deepToString(" ")
+ + "\"["
+ + Utils.idStringFromNan(mFloatPath[1])
+ + "] "
+ + mOutputPath[1]
+ + " ["
+ + Utils.idStringFromNan(mFloatPath[2])
+ + "] "
+ + mOutputPath[2];
}
public static final int MOVE = 10;
@@ -99,6 +112,11 @@
public static final float CLOSE_NAN = Utils.asNan(CLOSE);
public static final float DONE_NAN = Utils.asNan(DONE);
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -197,7 +215,9 @@
}
@Override
- public void paint(PaintContext context) {}
+ public void paint(PaintContext context) {
+ apply(context.getContext());
+ }
@Override
public void apply(@NonNull RemoteContext context) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 4ec5436..85a01fc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -38,6 +38,7 @@
int mInstanceId;
float[] mFloatPath;
float[] mOutputPath;
+ private boolean mPathChanged = true;
PathData(int instanceId, float[] floatPath) {
mInstanceId = instanceId;
@@ -50,7 +51,11 @@
for (int i = 0; i < mFloatPath.length; i++) {
float v = mFloatPath[i];
if (Utils.isVariable(v)) {
+ float tmp = mOutputPath[i];
mOutputPath[i] = Float.isNaN(v) ? context.getFloat(Utils.idFromNan(v)) : v;
+ if (tmp != mOutputPath[i]) {
+ mPathChanged = true;
+ }
} else {
mOutputPath[i] = v;
}
@@ -107,6 +112,11 @@
public static final float CLOSE_NAN = Utils.asNan(CLOSE);
public static final float DONE_NAN = Utils.asNan(DONE);
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -216,6 +226,9 @@
@Override
public void apply(@NonNull RemoteContext context) {
- context.loadPathData(mInstanceId, mOutputPath);
+ if (mPathChanged) {
+ context.loadPathData(mInstanceId, mOutputPath);
+ }
+ mPathChanged = false;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
index a6fa680..65adfea 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathTween.java
@@ -80,6 +80,11 @@
+ floatToString(mTween, mTweenOut);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index aaa7176..55dd882 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -200,6 +200,11 @@
return toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -239,6 +244,11 @@
operations.add(rootContentBehavior);
}
+ /**
+ * 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("Protocol Operations", OP_CODE, CLASS_NAME)
.description("Describes the behaviour of the root")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index e92daa3..ad86e0f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -24,11 +24,13 @@
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 com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
import java.util.List;
/** Describe a content description for the document */
-public class RootContentDescription extends Operation implements RemoteComposeOperation {
+public class RootContentDescription extends Operation
+ implements RemoteComposeOperation, AccessibleComponent {
private static final int OP_CODE = Operations.ROOT_CONTENT_DESCRIPTION;
private static final String CLASS_NAME = "RootContentDescription";
int mContentDescription;
@@ -43,6 +45,11 @@
}
@Override
+ public boolean isInterestingForSemantics() {
+ return mContentDescription != 0;
+ }
+
+ @Override
public void write(@NonNull WireBuffer buffer) {
apply(buffer, mContentDescription);
}
@@ -64,6 +71,16 @@
return toString();
}
+ @Override
+ public Integer getContentDescriptionId() {
+ return mContentDescription;
+ }
+
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index e2502fe..8e4098e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -198,6 +198,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index 3f679bf..d48de37 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -54,6 +54,11 @@
return "TextData[" + mTextId + "] = \"" + Utils.trimString(mText, 10) + "\"";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
index 4d01e0c..cc0ff02 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -122,6 +122,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
index 3ec6f01..dceb8b6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookup.java
@@ -79,6 +79,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
index 9c0ee53..823b706 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextLookupInt.java
@@ -72,6 +72,11 @@
context.listensTo(mIndex, this);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
index 5b0c38f..d695615 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -53,6 +53,11 @@
return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
index e329c38d..6c9105d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Theme.java
@@ -72,6 +72,11 @@
return indent + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
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 e2e20bc..f42abfc 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
@@ -21,6 +21,7 @@
import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -30,6 +31,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
import com.android.internal.widget.remotecompose.core.operations.utilities.NanMap;
import com.android.internal.widget.remotecompose.core.operations.utilities.touch.VelocityEasing;
@@ -80,14 +82,41 @@
int mTouchEffects;
float mVelocityId;
+ /** Stop with some deceleration */
public static final int STOP_GENTLY = 0;
+
+ /** Stop only at the start or end */
public static final int STOP_ENDS = 2;
+
+ /** Stop on touch up */
public static final int STOP_INSTANTLY = 1;
+
+ /** Stop at evenly spaced notches */
public static final int STOP_NOTCHES_EVEN = 3;
+
+ /** Stop at a collection points described in percents of the range */
public static final int STOP_NOTCHES_PERCENTS = 4;
+
+ /** Stop at a collectiond of point described in abslute cordnates */
public static final int STOP_NOTCHES_ABSOLUTE = 5;
+
+ /** Jump to the absloute poition of the point */
public static final int STOP_ABSOLUTE_POS = 6;
+ /**
+ * create a touch expression
+ *
+ * @param id The float id the value is output to
+ * @param exp the expression (containing TOUCH_* )
+ * @param defValue the default value
+ * @param min the minimum value
+ * @param max the maximum value
+ * @param touchEffects the type of touch mode
+ * @param velocityId the valocity (not used)
+ * @param stopMode the behavour on touch oup
+ * @param stopSpec the paraameters that affect the touch up behavour
+ * @param easingSpec the easing parameters for coming to a stop
+ */
public TouchExpression(
int id,
float[] exp,
@@ -129,7 +158,6 @@
@Override
public void updateVariables(RemoteContext context) {
-
if (mPreCalcValue == null || mPreCalcValue.length != mSrcExp.length) {
mPreCalcValue = new float[mSrcExp.length];
}
@@ -192,7 +220,9 @@
if (Float.isNaN(mDefValue)) {
context.listensTo(Utils.idFromNan(mDefValue), this);
}
- context.addTouchListener(this);
+ if (mComponent == null) {
+ context.addTouchListener(this);
+ }
for (float v : mSrcExp) {
if (Float.isNaN(v)
&& !AnimatedFloatExpression.isMathOperator(v)
@@ -332,9 +362,25 @@
float mScrLeft, mScrRight, mScrTop, mScrBottom;
- @Override
- public void apply(RemoteContext context) {
- Component comp = context.mLastComponent;
+ @Nullable Component mComponent;
+
+ /**
+ * Set the component the touch expression is in (if any)
+ * @param component the component, or null if outside
+ */
+ public void setComponent(@Nullable Component component) {
+ mComponent = component;
+ if (mComponent != null) {
+ try {
+ RootLayoutComponent root = mComponent.getRoot();
+ root.setHasTouchListeners(true);
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ private void updateBounds() {
+ Component comp = mComponent;
if (comp != null) {
float x = comp.getX();
float y = comp.getY();
@@ -351,7 +397,11 @@
mScrRight = w + x;
mScrBottom = h + y;
}
- updateVariables(context);
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ updateBounds();
if (mUnmodified) {
mCurrentValue = mOutDefValue;
context.loadFloat(mId, wrap(mCurrentValue));
@@ -371,6 +421,7 @@
mEasingToStop = false;
}
crossNotchCheck(context);
+ context.needsRepaint();
return;
}
if (mTouchDown) {
@@ -395,11 +446,11 @@
@Override
public void touchDown(RemoteContext context, float x, float y) {
-
if (!(x >= mScrLeft && x <= mScrRight && y >= mScrTop && y <= mScrBottom)) {
Utils.log("NOT IN WINDOW " + x + ", " + y + " " + mScrLeft + ", " + mScrTop);
return;
}
+ mEasingToStop = false;
mTouchDown = true;
mUnmodified = false;
if (mMode == 0) {
@@ -407,6 +458,7 @@
mDownTouchValue =
mExp.eval(context.getCollectionsAccess(), mPreCalcValue, mPreCalcValue.length);
}
+ context.needsRepaint();
}
@Override
@@ -441,6 +493,7 @@
float time = mMaxTime * Math.abs(dest - value) / (2 * mMaxVelocity);
mEasyTouch.config(value, dest, slope, time, mMaxAcceleration, mMaxVelocity, null);
mEasingToStop = true;
+ context.needsRepaint();
}
@Override
@@ -449,7 +502,7 @@
return;
}
apply(context);
- context.getDocument().getRootLayoutComponent().needsRepaint();
+ context.needsRepaint();
}
@Override
@@ -494,6 +547,12 @@
// ===================== static ======================
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return CLASS_NAME;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
index 0f84059..1c24160 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ActionOperation.java
@@ -23,8 +23,23 @@
/** Operations representing actions on the document */
public interface ActionOperation {
+ /**
+ * Serialize the string
+ *
+ * @param indent padding to display
+ * @param serializer append the string
+ */
void serializeToString(int indent, @NonNull StringSerializer serializer);
+ /**
+ * Run the action
+ *
+ * @param context remote context
+ * @param document document
+ * @param component component
+ * @param x the x location of the action
+ * @param y the y location of the action
+ */
void runAction(
@NonNull RemoteContext context,
@NonNull CoreDocument document,
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
index 19f4c2b..652ab2b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/AnimatableValue.java
@@ -20,6 +20,7 @@
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.GeneralEasing;
+/** Value animation for layouts */
public class AnimatableValue {
boolean mIsVariable = false;
int mId = 0;
@@ -34,6 +35,11 @@
int mMotionEasingType = GeneralEasing.CUBIC_STANDARD;
FloatAnimation mMotionEasing;
+ /**
+ * Value to animate
+ *
+ * @param value value
+ */
public AnimatableValue(float value) {
if (Utils.isVariable(value)) {
mId = Utils.idFromNan(value);
@@ -43,10 +49,21 @@
}
}
+ /**
+ * Get the value
+ *
+ * @return the value
+ */
public float getValue() {
return mValue;
}
+ /**
+ * Evaluate going through FloatAnimation if needed
+ *
+ * @param context the paint context
+ * @return the current value
+ */
public float evaluate(PaintContext context) {
if (!mIsVariable) {
return mValue;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
index 121b180..34b7a23 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/CanvasContent.java
@@ -41,6 +41,11 @@
super(parent, componentId, animationId, x, y, width, height);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "CanvasContent";
@@ -77,6 +82,11 @@
operations.add(new CanvasContent(componentId, 0, 0, 0, 0, null, -1));
}
+ /**
+ * 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("Layout Operations", id(), name())
.field(INT, "COMPONENT_ID", "unique id for this component")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
index 34c4249..dcf1d25 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java
@@ -16,6 +16,7 @@
package com.android.internal.widget.remotecompose.core.operations.layout;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
@@ -33,13 +34,15 @@
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.Easing;
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
import java.util.ArrayList;
import java.util.List;
/** Represents a click modifier + actions */
public class ClickModifierOperation extends PaintOperation
- implements ModifierOperation, DecoratorComponent, ClickHandler {
+ implements ModifierOperation, DecoratorComponent, ClickHandler, AccessibleComponent {
private static final int OP_CODE = Operations.MODIFIER_CLICK;
long mAnimateRippleStart = 0;
@@ -54,6 +57,22 @@
@NonNull PaintBundle mPaint = new PaintBundle();
+ @Override
+ public boolean isClickable() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Role getRole() {
+ return Role.BUTTON;
+ }
+
+ @Override
+ public CoreSemantics.Mode getMode() {
+ return CoreSemantics.Mode.MERGE;
+ }
+
public void animateRipple(float x, float y) {
mAnimateRippleStart = System.currentTimeMillis();
mAnimateRippleX = x;
@@ -80,6 +99,10 @@
@Override
public void apply(@NonNull RemoteContext context) {
+ RootLayoutComponent root = context.getDocument().getRootLayoutComponent();
+ if (root != null) {
+ root.setHasTouchListeners(true);
+ }
for (Operation op : mList) {
if (op instanceof TextData) {
op.apply(context);
@@ -136,7 +159,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
mWidth = width;
mHeight = height;
}
@@ -173,6 +197,11 @@
context.hapticEffect(3);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "ClickModifier";
@@ -192,6 +221,11 @@
operations.add(new ClickModifierOperation());
}
+ /**
+ * 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("Layout Operations", OP_CODE, name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
index faa259f..e95dfda 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java
@@ -28,6 +28,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.ComponentValue;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimateMeasure;
import com.android.internal.widget.remotecompose.core.operations.layout.animation.AnimationSpec;
import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure;
@@ -119,6 +120,17 @@
mHeight = value;
}
+ @Override
+ public void apply(@NonNull RemoteContext context) {
+ for (Operation op : mList) {
+ if (op instanceof VariableSupport && op.isDirty()) {
+ op.markNotDirty();
+ ((VariableSupport) op).updateVariables(context);
+ }
+ }
+ super.apply(context);
+ }
+
/**
* Utility function to update variables referencing this component dimensions
*
@@ -233,14 +245,6 @@
if (!mComponentValues.isEmpty()) {
updateComponentValues(context);
}
- for (Operation o : mList) {
- if (o instanceof Component) {
- ((Component) o).updateVariables(context);
- }
- if (o instanceof VariableSupport) {
- o.apply(context);
- }
- }
context.mLastComponent = prev;
}
@@ -248,14 +252,40 @@
mComponentValues.add(v);
}
- public float intrinsicWidth() {
+ /**
+ * Returns the intrinsic width of the layout
+ *
+ * @param context
+ * @return the width in pixels
+ */
+ public float intrinsicWidth(@Nullable RemoteContext context) {
return getWidth();
}
- public float intrinsicHeight() {
+ /**
+ * Returns the intrinsic height of the layout
+ *
+ * @param context
+ * @return the height in pixels
+ */
+ public float intrinsicHeight(@Nullable RemoteContext context) {
return getHeight();
}
+ /**
+ * This function is called after a component is created, with its mList initialized. This let
+ * the component a chance to do some post-initialization work on its children ops.
+ */
+ public void inflate() {
+ for (Operation op : mList) {
+ if (op instanceof TouchExpression) {
+ // Make sure to set the component of a touch expression that belongs to us!
+ TouchExpression touchExpression = (TouchExpression) op;
+ touchExpression.setComponent(this);
+ }
+ }
+ }
+
public enum Visibility {
GONE,
VISIBLE,
@@ -409,11 +439,23 @@
if (op instanceof TouchHandler) {
((TouchHandler) op).onTouchDown(context, document, this, cx, cy);
}
+ if (op instanceof TouchExpression) {
+ TouchExpression touchExpression = (TouchExpression) op;
+ touchExpression.updateVariables(context);
+ touchExpression.touchDown(context, cx, cy);
+ document.appliedTouchOperation(this);
+ }
}
}
public void onTouchUp(
- RemoteContext context, CoreDocument document, float x, float y, boolean force) {
+ RemoteContext context,
+ CoreDocument document,
+ float x,
+ float y,
+ float dx,
+ float dy,
+ boolean force) {
if (!force && !contains(x, y)) {
return;
}
@@ -421,10 +463,15 @@
float cy = y - getScrollY();
for (Operation op : mList) {
if (op instanceof Component) {
- ((Component) op).onTouchUp(context, document, cx, cy, force);
+ ((Component) op).onTouchUp(context, document, cx, cy, dx, dy, force);
}
if (op instanceof TouchHandler) {
- ((TouchHandler) op).onTouchUp(context, document, this, cx, cy);
+ ((TouchHandler) op).onTouchUp(context, document, this, cx, cy, dx, dy);
+ }
+ if (op instanceof TouchExpression) {
+ TouchExpression touchExpression = (TouchExpression) op;
+ touchExpression.updateVariables(context);
+ touchExpression.touchUp(context, cx, cy, dx, dy);
}
}
}
@@ -443,6 +490,11 @@
if (op instanceof TouchHandler) {
((TouchHandler) op).onTouchCancel(context, document, this, cx, cy);
}
+ if (op instanceof TouchExpression) {
+ TouchExpression touchExpression = (TouchExpression) op;
+ touchExpression.updateVariables(context);
+ touchExpression.touchUp(context, cx, cy, 0, 0);
+ }
}
}
@@ -460,6 +512,11 @@
if (op instanceof TouchHandler) {
((TouchHandler) op).onTouchDrag(context, document, this, cx, cy);
}
+ if (op instanceof TouchExpression) {
+ TouchExpression touchExpression = (TouchExpression) op;
+ touchExpression.updateVariables(context);
+ touchExpression.touchDrag(context, x, y);
+ }
}
}
@@ -641,6 +698,9 @@
}
public void paintingComponent(@NonNull PaintContext context) {
+ if (!mComponentValues.isEmpty()) {
+ updateComponentValues(context.getContext());
+ }
if (mPreTranslate != null) {
mPreTranslate.paint(context);
}
@@ -652,7 +712,15 @@
debugBox(this, context);
}
for (Operation op : mList) {
- op.apply(context.getContext());
+ if (op.isDirty() && op instanceof VariableSupport) {
+ ((VariableSupport) op).updateVariables(context.getContext());
+ op.markNotDirty();
+ }
+ if (op instanceof PaintOperation) {
+ ((PaintOperation) op).paint(context);
+ } else {
+ op.apply(context.getContext());
+ }
}
context.restore();
context.getContext().mLastComponent = prev;
@@ -661,7 +729,7 @@
public boolean applyAnimationAsNeeded(@NonNull PaintContext context) {
if (context.isAnimationEnabled() && mAnimateMeasure != null) {
mAnimateMeasure.apply(context);
- needsRepaint();
+ context.needsRepaint();
return true;
}
return false;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
index 396644c..5da0663 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentEnd.java
@@ -49,6 +49,11 @@
return (indent != null ? indent : "") + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "ComponentEnd";
@@ -81,6 +86,11 @@
operations.add(new ComponentEnd());
}
+ /**
+ * 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("Layout Operations", id(), name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
index a85ae27..4349b31 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ComponentStart.java
@@ -157,6 +157,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "ComponentStart";
@@ -198,6 +203,11 @@
operations.add(new ComponentStart(type, componentId, width, height));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
index d617007..9ca2f2e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/DecoratorComponent.java
@@ -24,5 +24,13 @@
* measured. Eg borders, background, clips, etc.
*/
public interface DecoratorComponent {
- void layout(@NonNull RemoteContext context, float width, float height);
+ /**
+ * Layout the decorator
+ *
+ * @param context
+ * @param component the associated component
+ * @param width horizontal dimension in pixels
+ * @param height vertical dimension in pixels
+ */
+ void layout(@NonNull RemoteContext context, Component component, float width, float height);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
index 7b0e4a2..e25392c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java
@@ -21,6 +21,8 @@
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.OperationInterface;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.operations.BitmapData;
import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
@@ -36,6 +38,7 @@
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.HeightModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.PaddingModifierOperation;
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ScrollModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.WidthModifierOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ZIndexModifierOperation;
@@ -54,6 +57,12 @@
protected float mPaddingTop = 0f;
protected float mPaddingBottom = 0f;
+ float mScrollX = 0f;
+ float mScrollY = 0f;
+
+ @Nullable protected ScrollDelegate mHorizontalScrollDelegate = null;
+ @Nullable protected ScrollDelegate mVerticalScrollDelegate = null;
+
@NonNull protected ComponentModifiers mComponentModifiers = new ComponentModifiers();
@NonNull
@@ -111,6 +120,7 @@
// Should be removed after ImageLayout is in
private static final boolean USE_IMAGE_TEMP_FIX = true;
+ @Override
public void inflate() {
ArrayList<TextData> data = new ArrayList<>();
ArrayList<Operation> supportedOperations = new ArrayList<>();
@@ -144,6 +154,7 @@
if (!canvasContent.mList.isEmpty()) {
mContent.mList.clear();
mChildrenComponents.add(canvasContent);
+ canvasContent.inflate();
}
} else {
content.getData(data);
@@ -155,6 +166,9 @@
if (op instanceof ComponentVisibilityOperation) {
((ComponentVisibilityOperation) op).setParent(this);
}
+ if (op instanceof ScrollModifierOperation) {
+ ((ScrollModifierOperation) op).inflate(this);
+ }
mComponentModifiers.add((ModifierOperation) op);
} else if (op instanceof TextData) {
data.add((TextData) op);
@@ -162,6 +176,9 @@
|| (op instanceof PaintData)
|| (op instanceof FloatExpression)) {
supportedOperations.add(op);
+ if (op instanceof TouchExpression) {
+ ((TouchExpression) op).setComponent(this);
+ }
} else {
// nothing
}
@@ -186,8 +203,6 @@
mPaddingRight = 0f;
mPaddingBottom = 0f;
- boolean applyHorizontalMargin = true;
- boolean applyVerticalMargin = true;
for (OperationInterface op : mComponentModifiers.getList()) {
if (op instanceof PaddingModifierOperation) {
// We are accumulating padding modifiers to compute the margin
@@ -209,6 +224,14 @@
mZIndexModifier = (ZIndexModifierOperation) op;
} else if (op instanceof GraphicsLayerModifierOperation) {
mGraphicsLayerModifier = (GraphicsLayerModifierOperation) op;
+ } else if (op instanceof ScrollDelegate) {
+ ScrollDelegate scrollDelegate = (ScrollDelegate) op;
+ if (scrollDelegate.handlesHorizontalScroll()) {
+ mHorizontalScrollDelegate = scrollDelegate;
+ }
+ if (scrollDelegate.handlesVerticalScroll()) {
+ mVerticalScrollDelegate = scrollDelegate;
+ }
}
}
if (mWidthModifier == null) {
@@ -217,8 +240,8 @@
if (mHeightModifier == null) {
mHeightModifier = new HeightModifierOperation(DimensionModifierOperation.Type.WRAP);
}
- setWidth(computeModifierDefinedWidth());
- setHeight(computeModifierDefinedHeight());
+ setWidth(computeModifierDefinedWidth(null));
+ setHeight(computeModifierDefinedHeight(null));
}
@NonNull
@@ -228,13 +251,36 @@
}
@Override
+ public void getLocationInWindow(@NonNull float[] value) {
+ value[0] += mX + mPaddingLeft;
+ value[1] += mY + mPaddingTop;
+ if (mParent != null) {
+ mParent.getLocationInWindow(value);
+ }
+ }
+
+ @Override
public float getScrollX() {
- return mComponentModifiers.getScrollX();
+ if (mHorizontalScrollDelegate != null) {
+ return mHorizontalScrollDelegate.getScrollX(mScrollX);
+ }
+ return mScrollX;
+ }
+
+ public void setScrollX(float value) {
+ mScrollX = value;
}
@Override
public float getScrollY() {
- return mComponentModifiers.getScrollY();
+ if (mVerticalScrollDelegate != null) {
+ return mVerticalScrollDelegate.getScrollY(mScrollY);
+ }
+ return mScrollY;
+ }
+
+ public void setScrollY(float value) {
+ mScrollY = value;
}
@Override
@@ -279,10 +325,18 @@
ArrayList<Component> sorted = new ArrayList<Component>(mChildrenComponents);
sorted.sort((a, b) -> (int) (a.getZIndex() - b.getZIndex()));
for (Component child : sorted) {
+ if (child.isDirty() && child instanceof VariableSupport) {
+ child.updateVariables(context.getContext());
+ child.markNotDirty();
+ }
child.paint(context);
}
} else {
for (Component child : mChildrenComponents) {
+ if (child.isDirty() && child instanceof VariableSupport) {
+ child.updateVariables(context.getContext());
+ child.markNotDirty();
+ }
child.paint(context);
}
}
@@ -295,11 +349,15 @@
}
/** Traverse the modifiers to compute indicated dimension */
- public float computeModifierDefinedWidth() {
+ public float computeModifierDefinedWidth(@Nullable RemoteContext context) {
float s = 0f;
float e = 0f;
float w = 0f;
for (OperationInterface c : mComponentModifiers.getList()) {
+ if (context != null && c.isDirty() && c instanceof VariableSupport) {
+ ((VariableSupport) c).updateVariables(context);
+ c.markNotDirty();
+ }
if (c instanceof WidthModifierOperation) {
WidthModifierOperation o = (WidthModifierOperation) c;
if (o.getType() == DimensionModifierOperation.Type.EXACT
@@ -339,11 +397,15 @@
}
/** Traverse the modifiers to compute indicated dimension */
- public float computeModifierDefinedHeight() {
+ public float computeModifierDefinedHeight(@Nullable RemoteContext context) {
float t = 0f;
float b = 0f;
float h = 0f;
for (OperationInterface c : mComponentModifiers.getList()) {
+ if (context != null && c.isDirty() && c instanceof VariableSupport) {
+ ((VariableSupport) c).updateVariables(context);
+ c.markNotDirty();
+ }
if (c instanceof HeightModifierOperation) {
HeightModifierOperation o = (HeightModifierOperation) c;
if (o.getType() == DimensionModifierOperation.Type.EXACT
@@ -383,6 +445,11 @@
}
@NonNull
+ public ComponentModifiers getComponentModifiers() {
+ return mComponentModifiers;
+ }
+
+ @NonNull
public ArrayList<Component> getChildrenComponents() {
return mChildrenComponents;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
index 20e4688..9bfbe6a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponentContent.java
@@ -41,6 +41,11 @@
super(parent, componentId, animationId, x, y, width, height);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "LayoutContent";
@@ -77,6 +82,11 @@
operations.add(new LayoutComponentContent(componentId, 0, 0, 0, 0, null, -1));
}
+ /**
+ * 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("Layout Operations", id(), name())
.field(INT, "COMPONENT_ID", "unique id for this component")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
index df960e4..505656e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java
@@ -32,8 +32,8 @@
implements ModifierOperation, DecoratorComponent {
String mOperationName;
- float mWidth = 0;
- float mHeight = 0;
+ protected float mWidth = 0;
+ protected float mHeight = 0;
private final float[] mLocationInWindow = new float[2];
@@ -71,7 +71,7 @@
public void paint(PaintContext context) {}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(RemoteContext context, Component component, float width, float height) {
mWidth = width;
mHeight = height;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
index d88f711..3d389e5 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopEnd.java
@@ -49,6 +49,11 @@
return (indent != null ? indent : "") + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "LoopEnd";
@@ -77,6 +82,11 @@
operations.add(new LoopEnd());
}
+ /**
+ * 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("Operations", id(), name()).description("End tag for loops");
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
index 83a2f0e..1b85681 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java
@@ -117,7 +117,7 @@
for (float i = mFromOut; i < mUntilOut; i += mStepOut) {
context.getContext().loadFloat(mIndexVariableId, i);
for (Operation op : mList) {
- if (op instanceof VariableSupport) {
+ if (op instanceof VariableSupport && op.isDirty()) {
((VariableSupport) op).updateVariables(context.getContext());
}
op.apply(context.getContext());
@@ -126,6 +126,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "Loop";
@@ -154,6 +159,11 @@
operations.add(new LoopOperation(indexId, from, step, until));
}
+ /**
+ * 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("Operations", OP_CODE, name())
.description("Loop. This operation execute" + " a list of action in a loop")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
index 99b7e68..12a673d 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/OperationsListEnd.java
@@ -49,6 +49,11 @@
return (indent != null ? indent : "") + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "ListEnd";
@@ -77,6 +82,11 @@
operations.add(new OperationsListEnd());
}
+ /**
+ * 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("Layout Operations", id(), name())
.description("End tag for list of operations.");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
index fd16287..11c0f3f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java
@@ -192,6 +192,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "RootLayout";
@@ -222,6 +227,11 @@
operations.add(new RootLayoutComponent(componentId, 0, 0, 0, 0, null, -1));
}
+ /**
+ * 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("Layout Operations", id(), name())
.field(INT, "COMPONENT_ID", "unique id for this component")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java
new file mode 100644
index 0000000..7ef9766
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ScrollDelegate.java
@@ -0,0 +1,58 @@
+/*
+ * 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.layout;
+
+/**
+ * Represent scroll delegates components.
+ *
+ * <p>Components have scroll X & Y properties. We can inject a scroll delegate as a modifier (e.g. a
+ * scrollView, a marquee...) to control the value of those properties.
+ */
+public interface ScrollDelegate {
+
+ /**
+ * Returns the horizontal scroll value
+ *
+ * @param currentValue the current value
+ * @return the value set by the delegate
+ */
+ float getScrollX(float currentValue);
+
+ /**
+ * Returns the vertical scroll value
+ *
+ * @param currentValue the current value
+ * @return the value set by the delegate
+ */
+ float getScrollY(float currentValue);
+
+ /**
+ * Returns true if the delegate can handle horizontal scroll
+ *
+ * @return true if the delegate handles horizontal scrolling
+ */
+ boolean handlesHorizontalScroll();
+
+ /**
+ * Returns true if the delegate can handle vertical scroll
+ *
+ * @return true if the delegate handles vertical scrolling
+ */
+ boolean handlesVerticalScroll();
+
+ /** Reset the delegate (e.g. the content of the component has changed) */
+ void reset();
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
index 3185bb5..4977a15 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchCancelModifierOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -60,7 +62,13 @@
@Override
public void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {
// nothing
}
@@ -76,6 +84,12 @@
// nothing
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return "TouchCancelModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
index d98911f..8c51f2e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchDownModifierOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -62,7 +64,13 @@
@Override
public void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {
// nothing
}
@@ -78,6 +86,12 @@
// nothing
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return "TouchModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
index ac9dd90..607060e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchHandler.java
@@ -41,9 +41,17 @@
* @param component the component on which the touch has been received
* @param x the x position of the click in document coordinates
* @param y the y position of the click in document coordinates
+ * @param dx
+ * @param dy
*/
void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y);
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy);
/**
* callback for a touch move event
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
index f6cb375..a12c356 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/TouchUpModifierOperation.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.widget.remotecompose.core.operations.layout;
+import android.annotation.NonNull;
+
import com.android.internal.widget.remotecompose.core.CoreDocument;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
@@ -60,7 +62,13 @@
@Override
public void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {
applyActions(context, document, component, x, y, true);
}
@@ -76,6 +84,12 @@
// nothing
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return "TouchUpModifier";
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
index b343099..2af3c73 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java
@@ -120,7 +120,7 @@
h -= pop.getTop() + pop.getBottom();
}
if (op instanceof DecoratorComponent) {
- ((DecoratorComponent) op).layout(context.getContext(), w, h);
+ ((DecoratorComponent) op).layout(context.getContext(), mComponent, w, h);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
index b230b09..6dff4a8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimationSpec.java
@@ -137,6 +137,11 @@
return (indent != null ? indent : "") + toString();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "AnimationSpec";
@@ -224,6 +229,11 @@
operations.add(op);
}
+ /**
+ * 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("Layout Operations", id(), name())
.description("define the animation")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
index 01cd7cc..8076cb1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/BoxLayout.java
@@ -119,8 +119,9 @@
size.setHeight(Math.max(size.getHeight(), m.getH()));
}
// add padding
- size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth()));
- size.setHeight(Math.max(size.getHeight(), computeModifierDefinedHeight()));
+ size.setWidth(Math.max(size.getWidth(), computeModifierDefinedWidth(context.getContext())));
+ size.setHeight(
+ Math.max(size.getHeight(), computeModifierDefinedHeight(context.getContext())));
}
@Override
@@ -172,6 +173,11 @@
}
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "BoxLayout";
@@ -219,6 +225,11 @@
verticalPositioning));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
index 665db26..0091a47 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/CanvasLayout.java
@@ -72,6 +72,11 @@
return "CANVAS";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "CanvasLayout";
@@ -104,6 +109,11 @@
operations.add(new CanvasLayout(null, componentId, animationId));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description("Canvas implementation. Encapsulate draw operations.\n\n")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
index 5b9ee0f..249e84a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/ColumnLayout.java
@@ -24,6 +24,7 @@
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
@@ -169,11 +170,11 @@
}
@Override
- public float intrinsicHeight() {
- float height = computeModifierDefinedHeight();
+ public float intrinsicHeight(@NonNull RemoteContext context) {
+ float height = computeModifierDefinedHeight(context);
float componentHeights = 0f;
for (Component c : mChildrenComponents) {
- componentHeights += c.intrinsicHeight();
+ componentHeights += c.intrinsicHeight(context);
}
return Math.max(height, componentHeights);
}
@@ -341,6 +342,11 @@
DebugLog.e();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "ColumnLayout";
@@ -392,6 +398,11 @@
spacedBy));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
index 6a15b7f..a5edaa8 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/LayoutManager.java
@@ -61,19 +61,19 @@
}
@Override
- public float intrinsicHeight() {
- float height = computeModifierDefinedHeight();
+ public float intrinsicHeight(@Nullable RemoteContext context) {
+ float height = computeModifierDefinedHeight(context);
for (Component c : mChildrenComponents) {
- height = Math.max(c.intrinsicHeight(), height);
+ height = Math.max(c.intrinsicHeight(context), height);
}
return height;
}
@Override
- public float intrinsicWidth() {
- float width = computeModifierDefinedWidth();
+ public float intrinsicWidth(@Nullable RemoteContext context) {
+ float width = computeModifierDefinedWidth(context);
for (Component c : mChildrenComponents) {
- width = Math.max(c.intrinsicWidth(), width);
+ width = Math.max(c.intrinsicWidth(context), width);
}
return width;
}
@@ -132,16 +132,17 @@
@NonNull MeasurePass measure) {
boolean hasWrap = true;
- float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth());
- float measuredHeight = Math.min(maxHeight, computeModifierDefinedHeight());
+ float measuredWidth = Math.min(maxWidth, computeModifierDefinedWidth(context.getContext()));
+ float measuredHeight =
+ Math.min(maxHeight, computeModifierDefinedHeight(context.getContext()));
float insetMaxWidth = maxWidth - mPaddingLeft - mPaddingRight;
float insetMaxHeight = maxHeight - mPaddingTop - mPaddingBottom;
if (mWidthModifier.isIntrinsicMin()) {
- maxWidth = intrinsicWidth();
+ maxWidth = intrinsicWidth(context.getContext());
}
if (mHeightModifier.isIntrinsicMin()) {
- maxHeight = intrinsicHeight();
+ maxHeight = intrinsicHeight(context.getContext());
}
boolean hasHorizontalWrap = mWidthModifier.isWrap();
@@ -180,7 +181,8 @@
if (isInHorizontalFill()) {
measuredWidth = maxWidth;
} else if (mWidthModifier.hasWeight()) {
- measuredWidth = Math.max(measuredWidth, computeModifierDefinedWidth());
+ measuredWidth =
+ Math.max(measuredWidth, computeModifierDefinedWidth(context.getContext()));
} else {
measuredWidth = Math.max(measuredWidth, minWidth);
measuredWidth = Math.min(measuredWidth, maxWidth);
@@ -188,7 +190,8 @@
if (isInVerticalFill()) { // todo: potential npe -- bbade@
measuredHeight = maxHeight;
} else if (mHeightModifier.hasWeight()) {
- measuredHeight = Math.max(measuredHeight, computeModifierDefinedHeight());
+ measuredHeight =
+ Math.max(measuredHeight, computeModifierDefinedHeight(context.getContext()));
} else {
measuredHeight = Math.max(measuredHeight, minHeight);
measuredHeight = Math.min(measuredHeight, maxHeight);
@@ -224,7 +227,9 @@
computeSize(context, 0f, measuredWidth, 0, h, measure);
mComponentModifiers.setVerticalScrollDimension(measuredHeight, h);
} else {
- computeSize(context, 0f, measuredWidth, 0f, measuredHeight, measure);
+ float maxChildWidth = measuredWidth - mPaddingLeft - mPaddingRight;
+ float maxChildHeight = measuredHeight - mPaddingTop - mPaddingBottom;
+ computeSize(context, 0f, maxChildWidth, 0f, maxChildHeight, measure);
}
}
@@ -258,7 +263,7 @@
super.layout(context, measure);
ComponentMeasure self = measure.get(this);
- mComponentModifiers.layout(context, self.getW(), self.getH());
+ mComponentModifiers.layout(context, this, self.getW(), self.getH());
for (Component c : mChildrenComponents) {
c.layout(context, measure);
}
@@ -275,7 +280,7 @@
super.layout(context, measure);
ComponentMeasure self = measure.get(this);
- mComponentModifiers.layout(context, self.getW(), self.getH());
+ mComponentModifiers.layout(context, this, self.getW(), self.getH());
this.mNeedsMeasure = false;
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
index 0ec820b..37b9a68 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/RowLayout.java
@@ -24,6 +24,7 @@
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
@@ -167,11 +168,11 @@
}
@Override
- public float intrinsicWidth() {
- float width = computeModifierDefinedWidth();
+ public float intrinsicWidth(@Nullable RemoteContext context) {
+ float width = computeModifierDefinedWidth(context);
float componentWidths = 0f;
for (Component c : mChildrenComponents) {
- componentWidths += c.intrinsicWidth();
+ componentWidths += c.intrinsicWidth(context);
}
return Math.max(width, componentWidths);
}
@@ -344,6 +345,11 @@
DebugLog.e();
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "RowLayout";
@@ -395,6 +401,11 @@
spacedBy));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
index 8e7f538..910205e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/managers/TextLayout.java
@@ -34,11 +34,13 @@
import com.android.internal.widget.remotecompose.core.operations.layout.measure.Size;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
import java.util.List;
/** Text component, referencing a text id */
-public class TextLayout extends LayoutManager implements ComponentStartOperation, VariableSupport {
+public class TextLayout extends LayoutManager
+ implements ComponentStartOperation, VariableSupport, AccessibleComponent {
private static final boolean DEBUG = false;
private int mTextId = -1;
@@ -57,6 +59,12 @@
@Nullable private String mCachedString = "";
+ @Nullable
+ @Override
+ public Integer getTextId() {
+ return mTextId;
+ }
+
@Override
public void registerListening(@NonNull RemoteContext context) {
if (mTextId != -1) {
@@ -92,6 +100,13 @@
}
mTextW = -1;
mTextH = -1;
+
+ if (mHorizontalScrollDelegate != null) {
+ mHorizontalScrollDelegate.reset();
+ }
+ if (mVerticalScrollDelegate != null) {
+ mVerticalScrollDelegate.reset();
+ }
invalidateMeasure();
}
@@ -175,6 +190,11 @@
int length = mCachedString.length();
if (mTextW > mWidth) {
context.save();
+ context.clipRect(
+ mPaddingLeft,
+ mPaddingTop,
+ mWidth - mPaddingLeft - mPaddingRight,
+ mHeight - mPaddingTop - mPaddingBottom);
context.translate(getScrollX(), getScrollY());
context.drawTextRun(mTextId, 0, length, 0, 0, mTextX, mTextY, false);
context.restore();
@@ -285,15 +305,20 @@
}
@Override
- public float intrinsicHeight() {
+ public float intrinsicHeight(@Nullable RemoteContext context) {
return mTextH;
}
@Override
- public float intrinsicWidth() {
+ public float intrinsicWidth(@Nullable RemoteContext context) {
return mTextW;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "TextLayout";
@@ -361,6 +386,11 @@
textAlign));
}
+ /**
+ * 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("Layout Operations", id(), name())
.description("Text layout implementation.\n\n")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
index 5df16c5..b4240d0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BackgroundModifierOperation.java
@@ -25,6 +25,7 @@
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
@@ -98,7 +99,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
@@ -109,6 +111,11 @@
return "BackgroundModifierOperation(" + mWidth + " x " + mHeight + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -182,6 +189,11 @@
context.restorePaint();
}
+ /**
+ * 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("Modifier Operations", OP_CODE, CLASS_NAME)
.description("define the Background Modifier")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
index bfadd2f..df30d9f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/BorderModifierOperation.java
@@ -25,6 +25,7 @@
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
@@ -124,7 +125,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
@@ -155,6 +157,11 @@
+ ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -240,6 +247,11 @@
context.restorePaint();
}
+ /**
+ * 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("Modifier Operations", OP_CODE, CLASS_NAME)
.description("define the Border Modifier")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
index d0af872..b27fb920 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ClipRectModifierOperation.java
@@ -23,6 +23,7 @@
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.List;
@@ -40,7 +41,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
@@ -55,6 +57,11 @@
apply(buffer);
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -83,6 +90,11 @@
operations.add(new ClipRectModifierOperation());
}
+ /**
+ * 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("Canvas Operations", OP_CODE, CLASS_NAME)
.description("Draw the specified round-rect");
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
index d11f26f..d2ba13f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java
@@ -21,6 +21,7 @@
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
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.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixSave;
@@ -86,6 +87,10 @@
float tx = 0f;
float ty = 0f;
for (ModifierOperation op : mList) {
+ if (op.isDirty() && op instanceof VariableSupport) {
+ ((VariableSupport) op).updateVariables(context.getContext());
+ op.markNotDirty();
+ }
if (op instanceof PaddingModifierOperation) {
PaddingModifierOperation pop = (PaddingModifierOperation) op;
context.translate(pop.getLeft(), pop.getTop());
@@ -109,7 +114,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
float w = width;
float h = height;
for (ModifierOperation op : mList) {
@@ -119,9 +125,9 @@
h -= pop.getTop() + pop.getBottom();
}
if (op instanceof ClickModifierOperation) {
- ((DecoratorComponent) op).layout(context, width, height);
+ ((DecoratorComponent) op).layout(context, component, width, height);
} else if (op instanceof DecoratorComponent) {
- ((DecoratorComponent) op).layout(context, w, h);
+ ((DecoratorComponent) op).layout(context, component, w, h);
}
}
}
@@ -156,10 +162,16 @@
@Override
public void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {
for (ModifierOperation op : mList) {
if (op instanceof TouchHandler) {
- ((TouchHandler) op).onTouchUp(context, document, component, x, y);
+ ((TouchHandler) op).onTouchUp(context, document, component, x, y, dx, dy);
}
}
}
@@ -208,32 +220,6 @@
return false;
}
- public float getScrollX() {
- float scroll = 0;
- for (ModifierOperation op : mList) {
- if (op instanceof ScrollModifierOperation) {
- ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
- if (scrollModifier.isHorizontalScroll()) {
- scroll = Math.min(scroll, scrollModifier.getScrollX());
- }
- }
- }
- return scroll;
- }
-
- public float getScrollY() {
- float scroll = 0;
- for (ModifierOperation op : mList) {
- if (op instanceof ScrollModifierOperation) {
- ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
- if (scrollModifier.isVerticalScroll()) {
- scroll = Math.min(scroll, scrollModifier.getScrollY());
- }
- }
- }
- return scroll;
- }
-
public void setHorizontalScrollDimension(float hostDimension, float contentDimension) {
for (ModifierOperation op : mList) {
if (op instanceof ScrollModifierOperation) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
index 1e6ccfc..c377b75 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentVisibilityOperation.java
@@ -90,6 +90,11 @@
operations.add(new ComponentVisibilityOperation(valueId));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "ComponentVisibility")
.description(
@@ -125,5 +130,6 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {}
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
index 4252309..15c2f46 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/GraphicsLayerModifierOperation.java
@@ -27,6 +27,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.layout.AnimatableValue;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.List;
@@ -202,6 +203,12 @@
return "GraphicsLayerModifierOperation(" + mScaleX + ", " + mScaleY + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return CLASS_NAME;
}
@@ -306,5 +313,5 @@
}
@Override
- public void layout(RemoteContext context, float width, float height) {}
+ public void layout(RemoteContext context, Component component, float width, float height) {}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
index 692b526..ec078a9 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HeightModifierOperation.java
@@ -32,6 +32,11 @@
private static final int OP_CODE = Operations.MODIFIER_HEIGHT;
public static final String CLASS_NAME = "HeightModifierOperation";
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -94,6 +99,11 @@
return "HEIGHT";
}
+ /**
+ * 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("Modifier Operations", OP_CODE, CLASS_NAME)
.description("define the animation")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
index 333e281..2e9d661 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostActionOperation.java
@@ -99,6 +99,11 @@
operations.add(new HostActionOperation(actionId));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "HostAction")
.description("Host action. This operation represents a host action")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
index f9a4270..49ef58e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/HostNamedActionOperation.java
@@ -125,6 +125,11 @@
operations.add(new HostNamedActionOperation(textId, type, valueId));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "HostNamedAction")
.description("Host Named action. This operation represents a host action")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
new file mode 100644
index 0000000..8b6d497
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
@@ -0,0 +1,216 @@
+/*
+ * 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.layout.modifiers;
+
+import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT;
+
+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.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.ScrollDelegate;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+
+import java.util.List;
+
+/** Represents a Marquee modifier. */
+public class MarqueeModifierOperation extends DecoratorModifierOperation implements ScrollDelegate {
+ private static final int OP_CODE = Operations.MODIFIER_MARQUEE;
+ public static final String CLASS_NAME = "MarqueeModifierOperation";
+
+ int mIterations;
+ int mAnimationMode;
+ float mRepeatDelayMillis;
+ float mInitialDelayMillis;
+ float mSpacing;
+ float mVelocity;
+
+ private float mComponentWidth;
+ private float mComponentHeight;
+ private float mContentWidth;
+ private float mContentHeight;
+
+ public MarqueeModifierOperation(
+ int iterations,
+ int animationMode,
+ float repeatDelayMillis,
+ float initialDelayMillis,
+ float spacing,
+ float velocity) {
+ this.mIterations = iterations;
+ this.mAnimationMode = animationMode;
+ this.mRepeatDelayMillis = repeatDelayMillis;
+ this.mInitialDelayMillis = initialDelayMillis;
+ this.mSpacing = spacing;
+ this.mVelocity = velocity;
+ }
+
+ public void setContentWidth(float value) {
+ mContentWidth = value;
+ }
+
+ public void setContentHeight(float value) {
+ mContentHeight = value;
+ }
+
+ @Override
+ public float getScrollX(float currentValue) {
+ return mScrollX;
+ }
+
+ @Override
+ public float getScrollY(float currentValue) {
+ return 0;
+ }
+
+ @Override
+ public boolean handlesHorizontalScroll() {
+ return true;
+ }
+
+ @Override
+ public boolean handlesVerticalScroll() {
+ return false;
+ }
+
+ /**
+ * Reset the modifier
+ */
+ public void reset() {
+ mLastTime = 0;
+ mScrollX = 0f;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ apply(
+ buffer,
+ mIterations,
+ mAnimationMode,
+ mRepeatDelayMillis,
+ mInitialDelayMillis,
+ mSpacing,
+ mVelocity);
+ }
+
+ // @Override
+ public void serializeToString(int indent, StringSerializer serializer) {
+ serializer.append(indent, "MARQUEE = [" + mIterations + "]");
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ private long mLastTime = 0;
+ private long mStartTime = 0;
+
+ private float mScrollX = 0f;
+
+ @Override
+ public void paint(PaintContext context) {
+ long currentTime = System.currentTimeMillis();
+ if (mLastTime == 0) {
+ mLastTime = currentTime;
+ mStartTime = mLastTime + (long) mInitialDelayMillis;
+ context.needsRepaint();
+ }
+ if (mContentWidth > mComponentWidth && currentTime - mStartTime > mInitialDelayMillis) {
+ float density = context.getContext().getDensity(); // in dp
+ float delta = mContentWidth - mComponentWidth;
+ float duration = delta / (density * mVelocity);
+ float elapsed = ((System.currentTimeMillis() - mStartTime) / 1000f);
+ elapsed = (elapsed % duration) / duration;
+ float offset =
+ (1f + (float) Math.sin(elapsed * 2 * Math.PI - Math.PI / 2f)) / 2f * -delta;
+
+ mScrollX = offset;
+ context.needsRepaint();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "MarqueeModifierOperation(" + mIterations + ")";
+ }
+
+ public static String name() {
+ return CLASS_NAME;
+ }
+
+ public static int id() {
+ return OP_CODE;
+ }
+
+ public static void apply(
+ WireBuffer buffer,
+ int iterations,
+ int animationMode,
+ float repeatDelayMillis,
+ float initialDelayMillis,
+ float spacing,
+ float velocity) {
+ buffer.start(OP_CODE);
+ buffer.writeInt(iterations);
+ buffer.writeInt(animationMode);
+ buffer.writeFloat(repeatDelayMillis);
+ buffer.writeFloat(initialDelayMillis);
+ buffer.writeFloat(spacing);
+ buffer.writeFloat(velocity);
+ }
+
+ public static void read(WireBuffer buffer, List<Operation> operations) {
+ int iterations = buffer.readInt();
+ int animationMode = buffer.readInt();
+ float repeatDelayMillis = buffer.readFloat();
+ float initialDelayMillis = buffer.readFloat();
+ float spacing = buffer.readFloat();
+ float velocity = buffer.readFloat();
+ operations.add(
+ new MarqueeModifierOperation(
+ iterations,
+ animationMode,
+ repeatDelayMillis,
+ initialDelayMillis,
+ spacing,
+ velocity));
+ }
+
+ public static void documentation(DocumentationBuilder doc) {
+ doc.operation("Modifier Operations", OP_CODE, CLASS_NAME)
+ .description("specify a Marquee Modifier")
+ .field(FLOAT, "value", "");
+ }
+
+ @Override
+ public void layout(RemoteContext context, Component component, float width, float height) {
+ mComponentWidth = width;
+ mComponentHeight = height;
+ if (component instanceof LayoutComponent) {
+ LayoutComponent layoutComponent = (LayoutComponent) component;
+ setContentWidth(layoutComponent.intrinsicWidth(context));
+ setContentHeight(layoutComponent.intrinsicHeight(context));
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
index 69c4e9a..4271947 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/OffsetModifierOperation.java
@@ -26,6 +26,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.List;
@@ -90,6 +91,12 @@
return "OffsetModifierOperation(" + mX + ", " + mY + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return CLASS_NAME;
}
@@ -123,5 +130,5 @@
}
@Override
- public void layout(RemoteContext context, float width, float height) {}
+ public void layout(RemoteContext context, Component component, float width, float height) {}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
index 545df64..bcfbdd6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/PaddingModifierOperation.java
@@ -113,6 +113,11 @@
+ ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -150,6 +155,11 @@
operations.add(new PaddingModifierOperation(left, top, right, bottom));
}
+ /**
+ * 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("Modifier Operations", OP_CODE, CLASS_NAME)
.description("define the Padding Modifier")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
new file mode 100644
index 0000000..fe074e4
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RippleModifierOperation.java
@@ -0,0 +1,192 @@
+/*
+ * 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.layout.modifiers;
+
+import android.annotation.NonNull;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler;
+import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
+import com.android.internal.widget.remotecompose.core.operations.utilities.ColorUtils;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.Easing;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
+
+import java.util.List;
+
+/** Represents a ripple effect */
+public class RippleModifierOperation extends DecoratorModifierOperation implements TouchHandler {
+ private static final int OP_CODE = Operations.MODIFIER_RIPPLE;
+
+ long mAnimateRippleStart = 0;
+ float mAnimateRippleX = 0f;
+ float mAnimateRippleY = 0f;
+ int mAnimateRippleDuration = 1000;
+
+ float mWidth = 0;
+ float mHeight = 0;
+
+ @NonNull public float[] locationInWindow = new float[2];
+
+ @NonNull PaintBundle mPaint = new PaintBundle();
+
+ /**
+ * Animate the ripple effect
+ *
+ * @param x
+ * @param y
+ */
+ public void animateRipple(float x, float y) {
+ mAnimateRippleStart = System.currentTimeMillis();
+ mAnimateRippleX = x;
+ mAnimateRippleY = y;
+ }
+
+ @Override
+ public void write(@NonNull WireBuffer buffer) {
+ apply(buffer);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "RippleModifier";
+ }
+
+ @Override
+ public void apply(@NonNull RemoteContext context) {
+ RootLayoutComponent root = context.getDocument().getRootLayoutComponent();
+ if (root != null) {
+ root.setHasTouchListeners(true);
+ }
+ }
+
+ @NonNull
+ @Override
+ public String deepToString(@NonNull String indent) {
+ return (indent != null ? indent : "") + toString();
+ }
+
+ @Override
+ public void paint(@NonNull PaintContext context) {
+ if (mAnimateRippleStart == 0) {
+ return;
+ }
+ context.needsRepaint();
+
+ float progress = (System.currentTimeMillis() - mAnimateRippleStart);
+ progress /= (float) mAnimateRippleDuration;
+ if (progress > 1f) {
+ mAnimateRippleStart = 0;
+ }
+ progress = Math.min(1f, progress);
+ context.save();
+ context.savePaint();
+ mPaint.reset();
+
+ FloatAnimation anim1 =
+ new FloatAnimation(Easing.CUBIC_STANDARD, 1f, null, Float.NaN, Float.NaN);
+ anim1.setInitialValue(0f);
+ anim1.setTargetValue(1f);
+ float tween = anim1.get(progress);
+
+ FloatAnimation anim2 =
+ new FloatAnimation(Easing.CUBIC_STANDARD, 0.5f, null, Float.NaN, Float.NaN);
+ anim2.setInitialValue(0f);
+ anim2.setTargetValue(1f);
+ float tweenRadius = anim2.get(progress);
+
+ int startColor = ColorUtils.createColor(250, 250, 250, 180);
+ int endColor = ColorUtils.createColor(200, 200, 200, 0);
+ int paintedColor = Utils.interpolateColor(startColor, endColor, tween);
+
+ float radius = Math.max(mWidth, mHeight) * tweenRadius;
+ mPaint.setColor(paintedColor);
+ context.applyPaint(mPaint);
+ context.clipRect(0f, 0f, mWidth, mHeight);
+ context.drawCircle(mAnimateRippleX, mAnimateRippleY, radius);
+ context.restorePaint();
+ context.restore();
+ }
+
+ @Override
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public void serializeToString(int indent, @NonNull StringSerializer serializer) {
+ serializer.append(indent, "RIPPLE_MODIFIER");
+ }
+
+ @NonNull
+ public static String name() {
+ return "RippleModifier";
+ }
+
+ public static void apply(@NonNull WireBuffer buffer) {
+ buffer.start(OP_CODE);
+ }
+
+ public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
+ operations.add(new RippleModifierOperation());
+ }
+
+ public static void documentation(@NonNull DocumentationBuilder doc) {
+ doc.operation("Layout Operations", OP_CODE, name())
+ .description(
+ "Ripple modifier. This modifier will do a ripple animation on touch down");
+ }
+
+ @Override
+ public void onTouchDown(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ locationInWindow[0] = 0f;
+ locationInWindow[1] = 0f;
+ component.getLocationInWindow(locationInWindow);
+ animateRipple(x - locationInWindow[0], y - locationInWindow[1]);
+ context.hapticEffect(3);
+ }
+
+ @Override
+ public void onTouchUp(
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {}
+
+ @Override
+ public void onTouchDrag(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {}
+
+ @Override
+ public void onTouchCancel(
+ RemoteContext context, CoreDocument document, Component component, float x, float y) {}
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
index 681501d..4c1f04e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/RoundedClipRectModifierOperation.java
@@ -26,6 +26,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.DrawBase4;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
@@ -57,6 +58,11 @@
return OP_CODE;
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -67,6 +73,11 @@
apply(buffer, v1, v2, v3, v4);
}
+ /**
+ * 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("Modifier Operations", id(), "RoundedClipRectModifierOperation")
.description("clip with rectangle")
@@ -107,7 +118,8 @@
}
@Override
- public void layout(@NonNull RemoteContext context, float width, float height) {
+ public void layout(
+ @NonNull RemoteContext context, Component component, float width, float height) {
this.mWidth = width;
this.mHeight = height;
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
index 0b66320..a5f79ee 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ScrollModifierOperation.java
@@ -24,18 +24,24 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
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.operations.TouchExpression;
import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.ListActionsOperation;
import com.android.internal.widget.remotecompose.core.operations.layout.RootLayoutComponent;
+import com.android.internal.widget.remotecompose.core.operations.layout.ScrollDelegate;
import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.List;
/** Represents a scroll modifier. */
-public class ScrollModifierOperation extends DecoratorModifierOperation implements TouchHandler {
+public class ScrollModifierOperation extends ListActionsOperation
+ implements TouchHandler, DecoratorComponent, ScrollDelegate, VariableSupport {
private static final int OP_CODE = Operations.MODIFIER_SCROLL;
public static final String CLASS_NAME = "ScrollModifierOperation";
@@ -43,9 +49,6 @@
private final float mMax;
private final float mNotchMax;
- float mWidth = 0;
- float mHeight = 0;
-
int mDirection;
float mTouchDownX;
@@ -63,13 +66,44 @@
float mHostDimension;
float mContentDimension;
+ private TouchExpression mTouchExpression;
+
public ScrollModifierOperation(int direction, float position, float max, float notchMax) {
+ super("SCROLL_MODIFIER");
this.mDirection = direction;
this.mPositionExpression = position;
this.mMax = max;
this.mNotchMax = notchMax;
}
+ /**
+ * Inflate the operation
+ *
+ * @param component
+ */
+ public void inflate(Component component) {
+ for (Operation op : mList) {
+ if (op instanceof TouchExpression) {
+ mTouchExpression = (TouchExpression) op;
+ mTouchExpression.setComponent(component);
+ }
+ }
+ }
+
+ @Override
+ public void registerListening(@NonNull RemoteContext context) {
+ if (mTouchExpression != null) {
+ mTouchExpression.registerListening(context);
+ }
+ }
+
+ @Override
+ public void updateVariables(@NonNull RemoteContext context) {
+ if (mTouchExpression != null) {
+ mTouchExpression.updateVariables(context);
+ }
+ }
+
public boolean isVerticalScroll() {
return mDirection == 0;
}
@@ -113,6 +147,12 @@
@Override
public void paint(PaintContext context) {
+ for (Operation op : mList) {
+ op.apply(context.getContext());
+ }
+ if (mTouchExpression == null) {
+ return;
+ }
float position =
context.getContext()
.mRemoteComposeState
@@ -130,6 +170,12 @@
return "ScrollModifierOperation(" + mDirection + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return CLASS_NAME;
}
@@ -167,7 +213,7 @@
}
@Override
- public void layout(RemoteContext context, float width, float height) {
+ public void layout(RemoteContext context, Component component, float width, float height) {
mWidth = width;
mHeight = height;
if (mDirection == 0) { // VERTICAL
@@ -186,18 +232,36 @@
mTouchDownY = y;
mInitialScrollX = mScrollX;
mInitialScrollY = mScrollY;
+ if (mTouchExpression != null) {
+ mTouchExpression.updateVariables(context);
+ mTouchExpression.touchDown(context, x + mScrollX, y + mScrollY);
+ }
document.appliedTouchOperation(component);
}
@Override
public void onTouchUp(
- RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ RemoteContext context,
+ CoreDocument document,
+ Component component,
+ float x,
+ float y,
+ float dx,
+ float dy) {
+ if (mTouchExpression != null) {
+ mTouchExpression.updateVariables(context);
+ mTouchExpression.touchUp(context, x + mScrollX, y + mScrollY, dx, dy);
+ }
// If not using touch expression, should add velocity decay here
}
@Override
public void onTouchDrag(
RemoteContext context, CoreDocument document, Component component, float x, float y) {
+ if (mTouchExpression != null) {
+ mTouchExpression.updateVariables(context);
+ mTouchExpression.touchDrag(context, x + mScrollX, y + mScrollY);
+ }
float dx = x - mTouchDownX;
float dy = y - mTouchDownY;
@@ -229,4 +293,35 @@
public float getContentDimension() {
return mContentDimension;
}
+
+ @Override
+ public float getScrollX(float currentValue) {
+ if (mDirection == 1) {
+ return mScrollX;
+ }
+ return 0f;
+ }
+
+ @Override
+ public float getScrollY(float currentValue) {
+ if (mDirection == 0) {
+ return mScrollY;
+ }
+ return 0f;
+ }
+
+ @Override
+ public boolean handlesHorizontalScroll() {
+ return mDirection == 1;
+ }
+
+ @Override
+ public boolean handlesVerticalScroll() {
+ return mDirection == 0;
+ }
+
+ @Override
+ public void reset() {
+ // nothing here for now
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
index b96d3cc..b6977a0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatChangeActionOperation.java
@@ -73,7 +73,6 @@
@Override
public void runAction(
RemoteContext context, CoreDocument document, Component component, float x, float y) {
- System.out.println("OVERRIDE " + mTargetValueId + " TO " + mValue);
context.overrideFloat(mTargetValueId, mValue);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
index d81b7ff..766271a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueFloatExpressionChangeActionOperation.java
@@ -101,6 +101,11 @@
operations.add(new ValueFloatExpressionChangeActionOperation(valueId, value));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation")
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
index fb13b42..60166a7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerChangeActionOperation.java
@@ -99,6 +99,11 @@
operations.add(new ValueIntegerChangeActionOperation(valueId, value));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "ValueIntegerChangeActionOperation")
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
index 0fe88ad..5025080 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueIntegerExpressionChangeActionOperation.java
@@ -101,6 +101,11 @@
operations.add(new ValueIntegerExpressionChangeActionOperation(valueId, value));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "ValueIntegerExpressionChangeActionOperation")
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
index a8d3b87..8093bb3 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ValueStringChangeActionOperation.java
@@ -103,6 +103,11 @@
operations.add(new ValueStringChangeActionOperation(valueId, value));
}
+ /**
+ * 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("Layout Operations", OP_CODE, "ValueStringChangeActionOperation")
.description(
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
index f6d743f..0530598 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/WidthModifierOperation.java
@@ -32,6 +32,11 @@
private static final int OP_CODE = Operations.MODIFIER_WIDTH;
public static final String CLASS_NAME = "WidthModifierOperation";
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return CLASS_NAME;
@@ -94,6 +99,11 @@
return "WIDTH";
}
+ /**
+ * 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("Modifier Operations", OP_CODE, CLASS_NAME)
.description("define the animation")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
index 96ed2cd..35de33a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ZIndexModifierOperation.java
@@ -26,6 +26,7 @@
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
import com.android.internal.widget.remotecompose.core.operations.Utils;
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
import java.util.List;
@@ -45,7 +46,7 @@
return mCurrentValue;
}
- public void setmValue(float value) {
+ public void setValue(float value) {
this.mValue = value;
}
@@ -79,6 +80,12 @@
return "ZIndexModifierOperation(" + mValue + ")";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
+ @NonNull
public static String name() {
return CLASS_NAME;
}
@@ -109,5 +116,5 @@
}
@Override
- public void layout(RemoteContext context, float width, float height) {}
+ public void layout(RemoteContext context, Component component, float width, float height) {}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
index a568747..7e46701 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
@@ -20,58 +20,147 @@
import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline;
+import java.util.Random;
+
/** high performance floating point expression evaluator used in animation */
public class AnimatedFloatExpression {
@NonNull static IntMap<String> sNames = new IntMap<>();
+
+ /** The START POINT in the float NaN space for operators */
public static final int OFFSET = 0x310_000;
+
+ /** ADD operator */
public static final float ADD = asNan(OFFSET + 1);
+
+ /** SUB operator */
public static final float SUB = asNan(OFFSET + 2);
+
+ /** MUL operator */
public static final float MUL = asNan(OFFSET + 3);
+
+ /** DIV operator */
public static final float DIV = asNan(OFFSET + 4);
+
+ /** MOD operator */
public static final float MOD = asNan(OFFSET + 5);
+
+ /** MIN operator */
public static final float MIN = asNan(OFFSET + 6);
+
+ /** MAX operator */
public static final float MAX = asNan(OFFSET + 7);
+
+ /** POW operator */
public static final float POW = asNan(OFFSET + 8);
+
+ /** SQRT operator */
public static final float SQRT = asNan(OFFSET + 9);
+
+ /** ABS operator */
public static final float ABS = asNan(OFFSET + 10);
+
+ /** SIGN operator */
public static final float SIGN = asNan(OFFSET + 11);
+
+ /** COPY_SIGN operator */
public static final float COPY_SIGN = asNan(OFFSET + 12);
+
+ /** EXP operator */
public static final float EXP = asNan(OFFSET + 13);
+
+ /** FLOOR operator */
public static final float FLOOR = asNan(OFFSET + 14);
+
+ /** LOG operator */
public static final float LOG = asNan(OFFSET + 15);
+
+ /** LN operator */
public static final float LN = asNan(OFFSET + 16);
+
+ /** ROUND operator */
public static final float ROUND = asNan(OFFSET + 17);
+
+ /** SIN operator */
public static final float SIN = asNan(OFFSET + 18);
+
+ /** COS operator */
public static final float COS = asNan(OFFSET + 19);
+
+ /** TAN operator */
public static final float TAN = asNan(OFFSET + 20);
+
+ /** ASIN operator */
public static final float ASIN = asNan(OFFSET + 21);
+
+ /** ACOS operator */
public static final float ACOS = asNan(OFFSET + 22);
+ /** ATAN operator */
public static final float ATAN = asNan(OFFSET + 23);
+ /** ATAN2 operator */
public static final float ATAN2 = asNan(OFFSET + 24);
+
+ /** MAD operator */
public static final float MAD = asNan(OFFSET + 25);
+
+ /** IFELSE operator */
public static final float IFELSE = asNan(OFFSET + 26);
+ /** CLAMP operator */
public static final float CLAMP = asNan(OFFSET + 27);
+
+ /** CBRT operator */
public static final float CBRT = asNan(OFFSET + 28);
+
+ /** DEG operator */
public static final float DEG = asNan(OFFSET + 29);
+
+ /** RAD operator */
public static final float RAD = asNan(OFFSET + 30);
+
+ /** CEIL operator */
public static final float CEIL = asNan(OFFSET + 31);
// Array ops
+ /** A DEREF operator */
public static final float A_DEREF = asNan(OFFSET + 32);
+
+ /** Array MAX operator */
public static final float A_MAX = asNan(OFFSET + 33);
+
+ /** Array MIN operator */
public static final float A_MIN = asNan(OFFSET + 34);
+
+ /** A_SUM operator */
public static final float A_SUM = asNan(OFFSET + 35);
+
+ /** A_AVG operator */
public static final float A_AVG = asNan(OFFSET + 36);
+
+ /** A_LEN operator */
public static final float A_LEN = asNan(OFFSET + 37);
+
+ /** A_SPLINE operator */
public static final float A_SPLINE = asNan(OFFSET + 38);
- public static final int LAST_OP = OFFSET + 38;
+ /** RAND Random number 0..1 */
+ public static final float RAND = asNan(OFFSET + 39);
- public static final float VAR1 = asNan(OFFSET + 39);
- public static final float VAR2 = asNan(OFFSET + 40);
+ /** RAND_SEED operator */
+ public static final float RAND_SEED = asNan(OFFSET + 40);
+
+ /** LAST valid operator */
+ public static final int LAST_OP = OFFSET + 40;
+
+ /** VAR1 operator */
+ public static final float VAR1 = asNan(OFFSET + 41);
+
+ /** VAR2 operator */
+ public static final float VAR2 = asNan(OFFSET + 42);
+
+ /** VAR2 operator */
+ public static final float VAR3 = asNan(OFFSET + 43);
// TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR
// private static final float FP_PI = (float) Math.PI;
@@ -83,6 +172,7 @@
@NonNull float[] mVar = new float[0];
@Nullable CollectionsAccess mCollectionsAccess;
IntMap<MonotonicSpline> mSplineMap = new IntMap<>();
+ private Random mRandom;
private float getSplineValue(int arrayId, float pos) {
MonotonicSpline fit = mSplineMap.get(arrayId);
@@ -151,10 +241,11 @@
/**
* Evaluate a float expression
*
- * @param ca
- * @param exp
- * @param var
- * @return
+ * @param ca Access to float array collections
+ * @param exp the expressions
+ * @param len the length of the expression array
+ * @param var variables if the expression contains VAR tags
+ * @return the value the expression evaluated to
*/
public float eval(
@NonNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var) {
@@ -183,9 +274,10 @@
/**
* Evaluate a float expression
*
- * @param ca
- * @param exp
- * @return
+ * @param ca The access to float arrays
+ * @param exp the expression
+ * @param len the length of the expression sections
+ * @return the value the expression evaluated to
*/
public float eval(@NonNull CollectionsAccess ca, @NonNull float[] exp, int len) {
System.arraycopy(exp, 0, mLocalStack, 0, len);
@@ -304,6 +396,8 @@
sNames.put(k++, "A_AVG");
sNames.put(k++, "A_LEN");
sNames.put(k++, "A_SPLINE");
+ sNames.put(k++, "RAND");
+ sNames.put(k++, "RAND_SEED");
sNames.put(k++, "a[0]");
sNames.put(k++, "a[1]");
@@ -518,9 +612,12 @@
private static final int OP_A_AVG = OFFSET + 36;
private static final int OP_A_LEN = OFFSET + 37;
private static final int OP_A_SPLINE = OFFSET + 38;
- private static final int OP_FIRST_VAR = OFFSET + 39;
- private static final int OP_SECOND_VAR = OFFSET + 40;
- private static final int OP_THIRD_VAR = OFFSET + 41;
+ private static final int OP_RAND = OFFSET + 39;
+ private static final int OP_RAND_SEED = OFFSET + 40;
+
+ private static final int OP_FIRST_VAR = OFFSET + 41;
+ private static final int OP_SECOND_VAR = OFFSET + 42;
+ private static final int OP_THIRD_VAR = OFFSET + 43;
int opEval(int sp, int id) {
float[] array;
@@ -708,6 +805,26 @@
mStack[sp - 1] = getSplineValue(id, mStack[sp]);
return sp - 1;
+ case OP_RAND:
+ if (mRandom == null) {
+ mRandom = new Random();
+ }
+ mStack[sp + 1] = mRandom.nextFloat();
+ return sp + 1;
+
+ case OP_RAND_SEED:
+ float seed = mStack[sp];
+ if (seed == 0) {
+ mRandom = new Random();
+ } else {
+ if (mRandom == null) {
+ mRandom = new Random(Float.floatToRawIntBits(seed));
+ } else {
+ mRandom.setSeed(Float.floatToRawIntBits(seed));
+ }
+ }
+ return sp - 1;
+
case OP_FIRST_VAR:
mStack[sp] = mVar[0];
return sp;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
index 182d36a..69de535 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ArrayAccess.java
@@ -23,17 +23,45 @@
* FloatArrayAccess, ListAccess, MapAccess
*/
public interface ArrayAccess {
+ /**
+ * Get a value as a float for an index
+ *
+ * @param index position in the collection
+ * @return
+ */
float getFloatValue(int index);
+ /**
+ * If the objects have id's return the id
+ *
+ * @param index index of the object
+ * @return id or -1 if no id is available
+ */
default int getId(int index) {
return 0;
}
+ /**
+ * Get the backing array of float if available for float arrays
+ *
+ * @return
+ */
@Nullable
float[] getFloats();
+ /**
+ * Get the length of the collection
+ *
+ * @return length of the collection
+ */
int getLength();
+ /**
+ * Get the value as an integer if available
+ *
+ * @param index the position in the collection
+ * @return it value as and integer
+ */
default int getIntValue(int index) {
return (int) getFloatValue(index);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java
new file mode 100644
index 0000000..cd8b7b8
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilityModifier.java
@@ -0,0 +1,23 @@
+/*
+ * 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.semantics;
+
+import com.android.internal.widget.remotecompose.core.operations.layout.modifiers.ModifierOperation;
+
+/** A Modifier that provides semantic info. */
+public interface AccessibilityModifier extends ModifierOperation, AccessibleComponent {
+ int getOpCode();
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java
new file mode 100644
index 0000000..291ad47
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibilitySemantics.java
@@ -0,0 +1,34 @@
+/*
+ * 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.semantics;
+
+/** Marker interface for a Component or Modifier that is relevant for Semantics. */
+public interface AccessibilitySemantics {
+
+ /**
+ * Determines if this element is interesting for semantic analysis.
+ *
+ * <p>This method is used to filter elements during semantic analysis. By default, all elements
+ * are considered interesting. Subclasses can override this method to exclude specific elements
+ * from semantic analysis.
+ *
+ * @return {@code true} if this element is interesting for semantic analysis, {@code false}
+ * otherwise.
+ */
+ default boolean isInterestingForSemantics() {
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java
new file mode 100644
index 0000000..e07fc4d
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/AccessibleComponent.java
@@ -0,0 +1,73 @@
+/*
+ * 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.semantics;
+
+import android.annotation.Nullable;
+
+public interface AccessibleComponent extends AccessibilitySemantics {
+ default @Nullable Integer getContentDescriptionId() {
+ return null;
+ }
+
+ default @Nullable Integer getTextId() {
+ return null;
+ }
+
+ default @Nullable Role getRole() {
+ return null;
+ }
+
+ default boolean isClickable() {
+ return false;
+ }
+
+ default CoreSemantics.Mode getMode() {
+ return CoreSemantics.Mode.SET;
+ }
+
+ // Our master list
+ // https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/Role
+ enum Role {
+ BUTTON("Button"),
+ CHECKBOX("Checkbox"),
+ SWITCH("Switch"),
+ RADIO_BUTTON("RadioButton"),
+ TAB("Tab"),
+ IMAGE("Image"),
+ DROPDOWN_LIST("DropdownList"),
+ PICKER("Picker"),
+ CAROUSEL("Carousel"),
+ UNKNOWN(null);
+
+ @Nullable private final String mDescription;
+
+ Role(@Nullable String description) {
+ this.mDescription = description;
+ }
+
+ @Nullable
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public static Role fromInt(int i) {
+ if (i < UNKNOWN.ordinal()) {
+ return Role.values()[i];
+ }
+ return Role.UNKNOWN;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
new file mode 100644
index 0000000..b8166e6
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
@@ -0,0 +1,148 @@
+/*
+ * 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.semantics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+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.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
+
+import java.util.List;
+
+/** Implementation of the most common semantics used in typical Android apps. */
+public class CoreSemantics extends Operation implements AccessibilityModifier {
+ public int mContentDescriptionId = 0;
+ public @Nullable Role mRole = null;
+ public int mTextId = 0;
+ public int mStateDescriptionId = 0;
+ public boolean mEnabled = true;
+ public Mode mMode = Mode.SET;
+ public boolean mClickable = false;
+
+ @Override
+ public int getOpCode() {
+ return Operations.ACCESSIBILITY_SEMANTICS;
+ }
+
+ @Nullable
+ @Override
+ public Role getRole() {
+ return mRole;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ buffer.writeInt(mContentDescriptionId);
+ buffer.writeByte((mRole != null) ? mRole.ordinal() : -1);
+ buffer.writeInt(mTextId);
+ buffer.writeInt(mStateDescriptionId);
+ buffer.writeByte(mMode.ordinal());
+ buffer.writeBoolean(mEnabled);
+ buffer.writeBoolean(mClickable);
+ }
+
+ private void read(WireBuffer buffer) {
+ mContentDescriptionId = buffer.readInt();
+ mRole = Role.fromInt(buffer.readByte());
+ mTextId = buffer.readInt();
+ mStateDescriptionId = buffer.readInt();
+ mMode = Mode.values()[buffer.readByte()];
+ mEnabled = buffer.readBoolean();
+ mClickable = buffer.readBoolean();
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ // Handled via touch helper
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SEMANTICS");
+ if (mRole != null) {
+ builder.append(" ");
+ builder.append(mRole);
+ }
+ if (mContentDescriptionId > 0) {
+ builder.append(" contentDescription=");
+ builder.append(mContentDescriptionId);
+ }
+ if (mTextId > 0) {
+ builder.append(" text=");
+ builder.append(mTextId);
+ }
+ if (mStateDescriptionId > 0) {
+ builder.append(" stateDescription=");
+ builder.append(mStateDescriptionId);
+ }
+ if (!mEnabled) {
+ builder.append(" disabled");
+ }
+ if (mClickable) {
+ builder.append(" clickable");
+ }
+ return builder.toString();
+ }
+
+ @Nullable
+ @Override
+ public String deepToString(String indent) {
+ return indent + this;
+ }
+
+ @NonNull
+ public String serializedName() {
+ return "SEMANTICS";
+ }
+
+ @Override
+ public void serializeToString(int indent, @NonNull StringSerializer serializer) {
+ serializer.append(indent, serializedName() + " = " + this);
+ }
+
+ public static void read(WireBuffer buffer, List<Operation> operations) {
+ CoreSemantics semantics = new CoreSemantics();
+
+ semantics.read(buffer);
+
+ operations.add(semantics);
+ }
+
+ @Override
+ public Integer getContentDescriptionId() {
+ return mContentDescriptionId != 0 ? mContentDescriptionId : null;
+ }
+
+ public @Nullable Integer getStateDescriptionId() {
+ return mStateDescriptionId != 0 ? mStateDescriptionId : null;
+ }
+
+ public @Nullable Integer getTextId() {
+ return mTextId != 0 ? mTextId : null;
+ }
+
+ public enum Mode {
+ SET,
+ CLEAR_AND_SET,
+ MERGE
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
index 975213f..2c874b1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/BooleanConstant.java
@@ -68,6 +68,11 @@
return "BooleanConstant[" + mId + "] = " + mValue + "";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "OrigamiBoolean";
@@ -108,6 +113,11 @@
operations.add(new BooleanConstant(id, value));
}
+ /**
+ * 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("Expressions Operations", OP_CODE, "BooleanConstant")
.description("A boolean and its associated id")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
index 210a15a..5462d3e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/IntegerConstant.java
@@ -60,6 +60,11 @@
return "IntegerConstant[" + mId + "] = " + mValue + "";
}
+ /**
+ * The name of the class
+ *
+ * @return the name
+ */
@NonNull
public static String name() {
return "IntegerConstant";
@@ -100,6 +105,11 @@
operations.add(new IntegerConstant(id, value));
}
+ /**
+ * 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("Expressions Operations", id(), "IntegerConstant")
.description("A integer and its associated id")
diff --git a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
index 9875c93..1a3cdb1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/types/LongConstant.java
@@ -96,6 +96,11 @@
operations.add(new LongConstant(id, value));
}
+ /**
+ * 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("Expressions Operations", OP_CODE, "LongConstant")
.description("A boolean and its associated id")
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 19b4b36..19453a0 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -85,6 +85,7 @@
}
} else {
mInner.setDocument(null);
+ this.setAccessibilityDelegate(null);
}
mapColors();
setupSensors();
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index bc7d5e1..daa44c8 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -250,7 +250,7 @@
@Override
public void getTextBounds(int textId, int start, int end, int flags, @NonNull float[] bounds) {
String str = getText(textId);
- if (end == -1) {
+ if (end == -1 || end > str.length()) {
end = str.length();
}
@@ -757,11 +757,17 @@
private Path getPath(int id, float start, float end) {
AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext;
+ Path p = (Path) androidContext.mRemoteComposeState.getPath(id);
+ if (p != null) {
+ return p;
+ }
Path path = new Path();
float[] pathData = androidContext.mRemoteComposeState.getPathData(id);
if (pathData != null) {
FloatsToPath.genPath(path, pathData, start, end);
+ androidContext.mRemoteComposeState.putPath(id, path);
}
+
return path;
}
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 ecfd13a..8da5b9d 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
@@ -241,9 +241,9 @@
case MotionEvent.ACTION_DOWN:
mActionDownPoint.x = (int) event.getX();
mActionDownPoint.y = (int) event.getY();
- mInActionDown = true;
CoreDocument doc = mDocument.getDocument();
if (doc.hasTouchListener()) {
+ mInActionDown = true;
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
@@ -251,8 +251,10 @@
}
mVelocityTracker.addMovement(event);
doc.touchDown(mARContext, event.getX(), event.getY());
+ invalidate();
+ return true;
}
- return true;
+ return false;
case MotionEvent.ACTION_CANCEL:
mInActionDown = false;
@@ -262,8 +264,10 @@
float dx = mVelocityTracker.getXVelocity(pointerId);
float dy = mVelocityTracker.getYVelocity(pointerId);
doc.touchCancel(mARContext, event.getX(), event.getY(), dx, dy);
+ invalidate();
+ return true;
}
- return true;
+
case MotionEvent.ACTION_UP:
mInActionDown = false;
performClick();
@@ -273,8 +277,9 @@
float dx = mVelocityTracker.getXVelocity(pointerId);
float dy = mVelocityTracker.getYVelocity(pointerId);
doc.touchUp(mARContext, event.getX(), event.getY(), dx, dy);
+ invalidate();
+ return true;
}
- return true;
case MotionEvent.ACTION_MOVE:
if (mInActionDown) {
@@ -286,6 +291,7 @@
invalidate();
}
}
+ return true;
}
}
return false;