Loading core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java +79 −2 Original line number Diff line number Diff line Loading @@ -16,20 +16,33 @@ package com.android.internal.widget.remotecompose.accessibility; import android.graphics.Rect; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import java.util.List; public class AndroidPlatformSemanticNodeApplier extends BaseSemanticNodeApplier<AccessibilityNodeInfo> { private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription"; private final View mPlayer; public AndroidPlatformSemanticNodeApplier(View player) { this.mPlayer = player; } @Override protected void setClickable(AccessibilityNodeInfo nodeInfo, boolean clickable) { nodeInfo.setClickable(clickable); if (clickable) { nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); nodeInfo.addAction(AccessibilityAction.ACTION_CLICK); } else { nodeInfo.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); nodeInfo.removeAction(AccessibilityAction.ACTION_CLICK); } } Loading Loading @@ -83,4 +96,68 @@ public class AndroidPlatformSemanticNodeApplier protected void setUniqueId(AccessibilityNodeInfo nodeInfo, String id) { nodeInfo.setUniqueId(id); } @Override protected void applyScrollable( AccessibilityNodeInfo nodeInfo, ScrollableComponent.ScrollAxisRange scrollAxis, int scrollDirection) { nodeInfo.setScrollable(true); nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION); nodeInfo.addAction(AccessibilityAction.ACTION_SET_PROGRESS); nodeInfo.setGranularScrollingSupported(true); if (scrollAxis.canScrollForward()) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD); if (scrollDirection == RootContentBehavior.SCROLL_VERTICAL) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_DOWN); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_DOWN); } else if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { // TODO handle RTL nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_RIGHT); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_RIGHT); } } if (scrollAxis.canScrollBackwards()) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD); if (scrollDirection == RootContentBehavior.SCROLL_VERTICAL) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_UP); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_UP); } else if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { // TODO handle RTL nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_LEFT); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_LEFT); } } // TODO correct values nodeInfo.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain(-1, 1, false)); if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { nodeInfo.setClassName("android.widget.HorizontalScrollView"); } else { nodeInfo.setClassName("android.widget.ScrollView"); } } @Override protected void applyListItem(AccessibilityNodeInfo nodeInfo, int parentId) { nodeInfo.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); nodeInfo.setScreenReaderFocusable(true); nodeInfo.setFocusable(true); nodeInfo.setParent(mPlayer, parentId); // TODO correct values nodeInfo.setCollectionItemInfo( AccessibilityNodeInfo.CollectionItemInfo.obtain(1, 1, 0, 1, false)); } @Override public void addChildren(AccessibilityNodeInfo nodeInfo, List<Integer> childIds) { for (int id : childIds) { nodeInfo.addChild(mPlayer, id); } } } core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java +31 −4 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.internal.widget.remotecompose.accessibility; import android.graphics.Rect; import android.util.Log; 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.semantics.AccessibilitySemantics; import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent.ScrollAxisRange; import java.util.List; Loading @@ -37,6 +41,8 @@ import java.util.List; * @param <N> The type of node this applier works with. */ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier<N> { private static final String LOG_TAG = "RemoteCompose"; @Override public void applyComponent( RemoteComposeDocumentAccessibility remoteComposeAccessibility, Loading Loading @@ -74,6 +80,15 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< if (getText(nodeInfo) == null && getContentDescription(nodeInfo) == null) { setContentDescription(nodeInfo, ""); } if (component.getParent() instanceof LayoutComponent) { LayoutComponent parent = (LayoutComponent) component.getParent(); ScrollableComponent scrollable = parent.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { applyListItem(nodeInfo, parent.getComponentId()); } } } protected void applySemantics( Loading Loading @@ -106,6 +121,15 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< } applyRole(accessibleComponent.getRole(), nodeInfo); } else if (semantic instanceof ScrollableComponent) { ScrollableComponent scrollableSemantic = (ScrollableComponent) semantic; if (scrollableSemantic.supportsScrollByOffset()) { ScrollAxisRange scrollAxis = scrollableSemantic.getScrollAxisRange(); applyScrollable(nodeInfo, scrollAxis, scrollableSemantic.scrollDirection()); } } else { Log.w(LOG_TAG, "Unknown semantic: " + semantic); } } } Loading Loading @@ -154,10 +178,8 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< N nodeInfo, RemoteComposeDocumentAccessibility remoteComposeAccessibility) { if (textId != null) { setText( nodeInfo, appendNullable( getText(nodeInfo), remoteComposeAccessibility.stringValue(textId))); String value = remoteComposeAccessibility.stringValue(textId); setText(nodeInfo, appendNullable(getText(nodeInfo), value)); } } Loading Loading @@ -205,4 +227,9 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< protected abstract void setBoundsInScreen(N nodeInfo, Rect bounds); protected abstract void setUniqueId(N nodeInfo, String s); protected abstract void applyScrollable( N nodeInfo, ScrollAxisRange scrollAxis, int scrollDirection); protected abstract void applyListItem(N nodeInfo, int parentId); } core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java +84 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.accessibility; import android.annotation.Nullable; import android.graphics.PointF; import android.os.Bundle; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; Loading @@ -31,6 +32,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier 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 com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -95,14 +97,90 @@ public class CoreDocumentAccessibility implements RemoteComposeDocumentAccessibi return result; } @Override public boolean performAction(Component component, int action, Bundle arguments) { if (action == ACTION_CLICK) { mDocument.performClick(mRemoteContext, component.getComponentId()); return true; boolean needsRepaint = true; try { if (isClickAction(action)) { return performClick(component); } else if (isScrollForwardAction(action)) { return scrollByOffset(mRemoteContext, component, -500) != 0; } else if (isScrollBackwardAction(action)) { return scrollByOffset(mRemoteContext, component, 500) != 0; } else if (isShowOnScreenAction(action)) { return showOnScreen(mRemoteContext, component); } else { needsRepaint = false; return false; } } finally { if (needsRepaint) { mDocument.needsRepaint(); } } } private static boolean isShowOnScreenAction(int action) { return action == android.R.id.accessibilityActionShowOnScreen; } private static boolean isScrollBackwardAction(int action) { return action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD || action == android.R.id.accessibilityActionScrollUp || action == android.R.id.accessibilityActionScrollLeft; } private static boolean isScrollForwardAction(int action) { return action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD || action == android.R.id.accessibilityActionScrollDown || action == android.R.id.accessibilityActionScrollRight; } private static boolean isClickAction(int action) { return action == AccessibilityNodeInfo.ACTION_CLICK; } private boolean showOnScreen(RemoteContext context, Component component) { if (component.getParent() instanceof LayoutComponent) { LayoutComponent parent = (LayoutComponent) component.getParent(); ScrollableComponent scrollable = parent.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { scrollable.showOnScreen(context, component.getComponentId()); return true; } } return false; } /** * scroll content by the given offset * * @param context * @param component * @param pixels * @return */ public int scrollByOffset(RemoteContext context, Component component, int pixels) { ScrollableComponent scrollable = component.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { return scrollable.scrollByOffset(context, pixels); } return 0; } /** * Perform a click on the given component * * @param component * @return */ public boolean performClick(Component component) { mDocument.performClick(mRemoteContext, component.getComponentId()); return true; } @Nullable Loading core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java +1 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ public class PlatformRemoteComposeAccessibilityRegistrar player, new CoreDocumentAccessibility( coreDocument, ((RemoteContextAware) player).getRemoteContext()), new AndroidPlatformSemanticNodeApplier()); new AndroidPlatformSemanticNodeApplier(player)); } public void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document) { Loading core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java +24 −32 Original line number Diff line number Diff line Loading @@ -33,10 +33,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent.Mode; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Stack; public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { private final RemoteComposeDocumentAccessibility mRemoteDocA11y; Loading @@ -58,7 +55,7 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { player, new CoreDocumentAccessibility( coreDocument, ((RemoteContextAware) player).getRemoteContext()), new AndroidPlatformSemanticNodeApplier()); new AndroidPlatformSemanticNodeApplier(player)); } /** Loading Loading @@ -96,35 +93,17 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { */ @Override protected void getVisibleVirtualViews(IntArray virtualViewIds) { Stack<Integer> toVisit = new Stack<>(); Set<Integer> visited = new HashSet<>(); Component rootComponent = mRemoteDocA11y.findComponentById(RootId); toVisit.push(RootId); while (!toVisit.isEmpty()) { Integer componentId = toVisit.remove(0); if (visited.add(componentId)) { Component component = mRemoteDocA11y.findComponentById(componentId); // Only include the root when it has semantics such as content description if (!RootId.equals(componentId) || !mRemoteDocA11y.semanticModifiersForComponent(component).isEmpty()) { virtualViewIds.add(componentId); if (rootComponent == null || !mRemoteDocA11y.semanticModifiersForComponent(rootComponent).isEmpty()) { virtualViewIds.add(RootId); } if (component != null) { Mode mergeMode = mRemoteDocA11y.mergeMode(component); if (mergeMode == Mode.SET) { List<Integer> childViews = mRemoteDocA11y.semanticallyRelevantChildComponents( component, false); toVisit.addAll(childViews); } } } List<Integer> children = mRemoteDocA11y.semanticallyRelevantChildComponents(rootComponent, false); for (int child : children) { virtualViewIds.add(child); } } Loading @@ -150,6 +129,13 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { List<AccessibilitySemantics> semantics = mRemoteDocA11y.semanticModifiersForComponent(component); mApplier.applyComponent(mRemoteDocA11y, node, component, semantics); if (mergeMode == Mode.SET) { List<Integer> childViews = mRemoteDocA11y.semanticallyRelevantChildComponents(component, false); mApplier.addChildren(node, childViews); } } @Override Loading @@ -161,7 +147,13 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { Component component = mRemoteDocA11y.findComponentById(virtualViewId); if (component != null) { return mRemoteDocA11y.performAction(component, action, arguments); boolean performed = mRemoteDocA11y.performAction(component, action, arguments); if (performed) { invalidateRoot(); } return performed; } else { return false; } Loading Loading
core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java +79 −2 Original line number Diff line number Diff line Loading @@ -16,20 +16,33 @@ package com.android.internal.widget.remotecompose.accessibility; import android.graphics.Rect; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import java.util.List; public class AndroidPlatformSemanticNodeApplier extends BaseSemanticNodeApplier<AccessibilityNodeInfo> { private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription"; private final View mPlayer; public AndroidPlatformSemanticNodeApplier(View player) { this.mPlayer = player; } @Override protected void setClickable(AccessibilityNodeInfo nodeInfo, boolean clickable) { nodeInfo.setClickable(clickable); if (clickable) { nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); nodeInfo.addAction(AccessibilityAction.ACTION_CLICK); } else { nodeInfo.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK); nodeInfo.removeAction(AccessibilityAction.ACTION_CLICK); } } Loading Loading @@ -83,4 +96,68 @@ public class AndroidPlatformSemanticNodeApplier protected void setUniqueId(AccessibilityNodeInfo nodeInfo, String id) { nodeInfo.setUniqueId(id); } @Override protected void applyScrollable( AccessibilityNodeInfo nodeInfo, ScrollableComponent.ScrollAxisRange scrollAxis, int scrollDirection) { nodeInfo.setScrollable(true); nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION); nodeInfo.addAction(AccessibilityAction.ACTION_SET_PROGRESS); nodeInfo.setGranularScrollingSupported(true); if (scrollAxis.canScrollForward()) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD); if (scrollDirection == RootContentBehavior.SCROLL_VERTICAL) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_DOWN); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_DOWN); } else if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { // TODO handle RTL nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_RIGHT); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_RIGHT); } } if (scrollAxis.canScrollBackwards()) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD); if (scrollDirection == RootContentBehavior.SCROLL_VERTICAL) { nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_UP); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_UP); } else if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { // TODO handle RTL nodeInfo.addAction(AccessibilityAction.ACTION_SCROLL_LEFT); nodeInfo.addAction(AccessibilityAction.ACTION_PAGE_LEFT); } } // TODO correct values nodeInfo.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain(-1, 1, false)); if (scrollDirection == RootContentBehavior.SCROLL_HORIZONTAL) { nodeInfo.setClassName("android.widget.HorizontalScrollView"); } else { nodeInfo.setClassName("android.widget.ScrollView"); } } @Override protected void applyListItem(AccessibilityNodeInfo nodeInfo, int parentId) { nodeInfo.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); nodeInfo.setScreenReaderFocusable(true); nodeInfo.setFocusable(true); nodeInfo.setParent(mPlayer, parentId); // TODO correct values nodeInfo.setCollectionItemInfo( AccessibilityNodeInfo.CollectionItemInfo.obtain(1, 1, 0, 1, false)); } @Override public void addChildren(AccessibilityNodeInfo nodeInfo, List<Integer> childIds) { for (int id : childIds) { nodeInfo.addChild(mPlayer, id); } } }
core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java +31 −4 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.internal.widget.remotecompose.accessibility; import android.graphics.Rect; import android.util.Log; 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.semantics.AccessibilitySemantics; import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent; import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent.ScrollAxisRange; import java.util.List; Loading @@ -37,6 +41,8 @@ import java.util.List; * @param <N> The type of node this applier works with. */ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier<N> { private static final String LOG_TAG = "RemoteCompose"; @Override public void applyComponent( RemoteComposeDocumentAccessibility remoteComposeAccessibility, Loading Loading @@ -74,6 +80,15 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< if (getText(nodeInfo) == null && getContentDescription(nodeInfo) == null) { setContentDescription(nodeInfo, ""); } if (component.getParent() instanceof LayoutComponent) { LayoutComponent parent = (LayoutComponent) component.getParent(); ScrollableComponent scrollable = parent.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { applyListItem(nodeInfo, parent.getComponentId()); } } } protected void applySemantics( Loading Loading @@ -106,6 +121,15 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< } applyRole(accessibleComponent.getRole(), nodeInfo); } else if (semantic instanceof ScrollableComponent) { ScrollableComponent scrollableSemantic = (ScrollableComponent) semantic; if (scrollableSemantic.supportsScrollByOffset()) { ScrollAxisRange scrollAxis = scrollableSemantic.getScrollAxisRange(); applyScrollable(nodeInfo, scrollAxis, scrollableSemantic.scrollDirection()); } } else { Log.w(LOG_TAG, "Unknown semantic: " + semantic); } } } Loading Loading @@ -154,10 +178,8 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< N nodeInfo, RemoteComposeDocumentAccessibility remoteComposeAccessibility) { if (textId != null) { setText( nodeInfo, appendNullable( getText(nodeInfo), remoteComposeAccessibility.stringValue(textId))); String value = remoteComposeAccessibility.stringValue(textId); setText(nodeInfo, appendNullable(getText(nodeInfo), value)); } } Loading Loading @@ -205,4 +227,9 @@ public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier< protected abstract void setBoundsInScreen(N nodeInfo, Rect bounds); protected abstract void setUniqueId(N nodeInfo, String s); protected abstract void applyScrollable( N nodeInfo, ScrollAxisRange scrollAxis, int scrollDirection); protected abstract void applyListItem(N nodeInfo, int parentId); }
core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java +84 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.widget.remotecompose.accessibility; import android.annotation.Nullable; import android.graphics.PointF; import android.os.Bundle; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.widget.remotecompose.core.CoreDocument; import com.android.internal.widget.remotecompose.core.Operation; Loading @@ -31,6 +32,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.modifier 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 com.android.internal.widget.remotecompose.core.semantics.ScrollableComponent; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -95,14 +97,90 @@ public class CoreDocumentAccessibility implements RemoteComposeDocumentAccessibi return result; } @Override public boolean performAction(Component component, int action, Bundle arguments) { if (action == ACTION_CLICK) { mDocument.performClick(mRemoteContext, component.getComponentId()); return true; boolean needsRepaint = true; try { if (isClickAction(action)) { return performClick(component); } else if (isScrollForwardAction(action)) { return scrollByOffset(mRemoteContext, component, -500) != 0; } else if (isScrollBackwardAction(action)) { return scrollByOffset(mRemoteContext, component, 500) != 0; } else if (isShowOnScreenAction(action)) { return showOnScreen(mRemoteContext, component); } else { needsRepaint = false; return false; } } finally { if (needsRepaint) { mDocument.needsRepaint(); } } } private static boolean isShowOnScreenAction(int action) { return action == android.R.id.accessibilityActionShowOnScreen; } private static boolean isScrollBackwardAction(int action) { return action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD || action == android.R.id.accessibilityActionScrollUp || action == android.R.id.accessibilityActionScrollLeft; } private static boolean isScrollForwardAction(int action) { return action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD || action == android.R.id.accessibilityActionScrollDown || action == android.R.id.accessibilityActionScrollRight; } private static boolean isClickAction(int action) { return action == AccessibilityNodeInfo.ACTION_CLICK; } private boolean showOnScreen(RemoteContext context, Component component) { if (component.getParent() instanceof LayoutComponent) { LayoutComponent parent = (LayoutComponent) component.getParent(); ScrollableComponent scrollable = parent.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { scrollable.showOnScreen(context, component.getComponentId()); return true; } } return false; } /** * scroll content by the given offset * * @param context * @param component * @param pixels * @return */ public int scrollByOffset(RemoteContext context, Component component, int pixels) { ScrollableComponent scrollable = component.selfOrModifier(ScrollableComponent.class); if (scrollable != null) { return scrollable.scrollByOffset(context, pixels); } return 0; } /** * Perform a click on the given component * * @param component * @return */ public boolean performClick(Component component) { mDocument.performClick(mRemoteContext, component.getComponentId()); return true; } @Nullable Loading
core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java +1 −1 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ public class PlatformRemoteComposeAccessibilityRegistrar player, new CoreDocumentAccessibility( coreDocument, ((RemoteContextAware) player).getRemoteContext()), new AndroidPlatformSemanticNodeApplier()); new AndroidPlatformSemanticNodeApplier(player)); } public void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document) { Loading
core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java +24 −32 Original line number Diff line number Diff line Loading @@ -33,10 +33,7 @@ import com.android.internal.widget.remotecompose.core.operations.layout.Componen import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics; import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent.Mode; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Stack; public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { private final RemoteComposeDocumentAccessibility mRemoteDocA11y; Loading @@ -58,7 +55,7 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { player, new CoreDocumentAccessibility( coreDocument, ((RemoteContextAware) player).getRemoteContext()), new AndroidPlatformSemanticNodeApplier()); new AndroidPlatformSemanticNodeApplier(player)); } /** Loading Loading @@ -96,35 +93,17 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { */ @Override protected void getVisibleVirtualViews(IntArray virtualViewIds) { Stack<Integer> toVisit = new Stack<>(); Set<Integer> visited = new HashSet<>(); Component rootComponent = mRemoteDocA11y.findComponentById(RootId); toVisit.push(RootId); while (!toVisit.isEmpty()) { Integer componentId = toVisit.remove(0); if (visited.add(componentId)) { Component component = mRemoteDocA11y.findComponentById(componentId); // Only include the root when it has semantics such as content description if (!RootId.equals(componentId) || !mRemoteDocA11y.semanticModifiersForComponent(component).isEmpty()) { virtualViewIds.add(componentId); if (rootComponent == null || !mRemoteDocA11y.semanticModifiersForComponent(rootComponent).isEmpty()) { virtualViewIds.add(RootId); } if (component != null) { Mode mergeMode = mRemoteDocA11y.mergeMode(component); if (mergeMode == Mode.SET) { List<Integer> childViews = mRemoteDocA11y.semanticallyRelevantChildComponents( component, false); toVisit.addAll(childViews); } } } List<Integer> children = mRemoteDocA11y.semanticallyRelevantChildComponents(rootComponent, false); for (int child : children) { virtualViewIds.add(child); } } Loading @@ -150,6 +129,13 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { List<AccessibilitySemantics> semantics = mRemoteDocA11y.semanticModifiersForComponent(component); mApplier.applyComponent(mRemoteDocA11y, node, component, semantics); if (mergeMode == Mode.SET) { List<Integer> childViews = mRemoteDocA11y.semanticallyRelevantChildComponents(component, false); mApplier.addChildren(node, childViews); } } @Override Loading @@ -161,7 +147,13 @@ public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper { Component component = mRemoteDocA11y.findComponentById(virtualViewId); if (component != null) { return mRemoteDocA11y.performAction(component, action, arguments); boolean performed = mRemoteDocA11y.performAction(component, action, arguments); if (performed) { invalidateRoot(); } return performed; } else { return false; } Loading