Skip to content

Commit

Permalink
feat: add snapshotMaxDepth to be able to detect deep depth elements (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
yoshitaka-ogata authored Jun 20, 2023
1 parent 3725bab commit 9a40742
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.appium.uiautomator2.model.internal.CustomUiDevice;
import io.appium.uiautomator2.model.settings.Settings;
import io.appium.uiautomator2.model.settings.SimpleBoundsCalculation;
import io.appium.uiautomator2.model.settings.SnapshotMaxDepth;
import io.appium.uiautomator2.utils.Logger;

import static io.appium.uiautomator2.utils.Device.getUiDevice;
Expand All @@ -48,8 +49,6 @@
* This class contains static helper methods to work with {@link AccessibilityNodeInfo}
*/
public class AxNodeInfoHelper {
// https://github.com/appium/appium/issues/12892
private static final int MAX_DEPTH = 70;
private static final long UNDEFINED_NODE_ID =
(((long) Integer.MAX_VALUE) << 32) | Integer.MAX_VALUE;
private static final int UNDEFINED_WINDOW_ID = -1;
Expand Down Expand Up @@ -233,7 +232,7 @@ public static int calculateIndex(AccessibilityNodeInfo node) {
}

/**
* Returns the node's bounds clipped to the size of the display, limited by the MAX_DEPTH
* Returns the node's bounds clipped to the size of the display, limited by the SnapshotMaxDepth
* The implementation is borrowed from `getVisibleBounds` method of `UiObject2` class
*
* @return Empty rect if node is null, else a Rect containing visible bounds
Expand Down Expand Up @@ -263,7 +262,8 @@ private static Rect getBounds(@Nullable AccessibilityNodeInfo node, Rect display
Set<AccessibilityNodeInfo> ancestors = new HashSet<>();
AccessibilityNodeInfo ancestor = node.getParent();
// An erroneous situation is possible where node parent equals to the node itself
while (++currentDepth < MAX_DEPTH && ancestor != null && !ancestors.contains(ancestor)) {
while (++currentDepth < Settings.get(SnapshotMaxDepth.class).getValue()
&& ancestor != null && !ancestors.contains(ancestor)) {
// If this ancestor is scrollable
if (ancestor.isScrollable()) {
// Trim any portion of the bounds that are hidden by the non-visible portion of our
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import io.appium.uiautomator2.core.AxNodeInfoHelper;
import io.appium.uiautomator2.model.settings.AllowInvisibleElements;
import io.appium.uiautomator2.model.settings.IncludeExtrasInPageSource;
import io.appium.uiautomator2.model.settings.SnapshotMaxDepth;
import io.appium.uiautomator2.model.settings.Settings;
import io.appium.uiautomator2.utils.Attribute;
import io.appium.uiautomator2.utils.Logger;
Expand All @@ -55,8 +56,6 @@
@TargetApi(18)
public class UiElementSnapshot extends UiElement<AccessibilityNodeInfo, UiElementSnapshot> {
private final static String ROOT_NODE_NAME = "hierarchy";
// https://github.com/appium/appium/issues/12545
private final static int DEFAULT_MAX_DEPTH = 70;
// The same order will be used for node attributes in xml page source
public final static Attribute[] SUPPORTED_ATTRIBUTES = new Attribute[]{
Attribute.INDEX, Attribute.PACKAGE, Attribute.CLASS, Attribute.TEXT,
Expand Down Expand Up @@ -95,15 +94,15 @@ private UiElementSnapshot(AccessibilityNodeInfo node, int index, int depth, int

private UiElementSnapshot(AccessibilityNodeInfo node, int index, int depth,
Set<Attribute> includedAttributes) {
this(node, index, depth, DEFAULT_MAX_DEPTH, includedAttributes);
this(node, index, depth, Settings.get(SnapshotMaxDepth.class).getValue(), includedAttributes);
}

private UiElementSnapshot(AccessibilityNodeInfo[] childNodes,
Set<Attribute> includedAttributes) {
super(null);
this.depth = 0;
this.index = 0;
this.maxDepth = DEFAULT_MAX_DEPTH;
this.maxDepth = Settings.get(SnapshotMaxDepth.class).getValue();
Map<Attribute, Object> attribs = new LinkedHashMap<>();
putAttribute(attribs, Attribute.INDEX, this.index);
putAttribute(attribs, Attribute.CLASS, ROOT_NODE_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public enum Settings {
MJPEG_SCALING_FACTOR(new MjpegScalingFactor()),
MJPEG_SERVER_SCREENSHOT_QUALITY(new MjpegServerScreenshotQuality()),
MJPEG_BILINEAR_FILTERING(new MjpegBilinearFiltering()),
USE_RESOURCES_FOR_ORIENTATION_DETECTION(new UseResourcesForOrientationDetection());
USE_RESOURCES_FOR_ORIENTATION_DETECTION(new UseResourcesForOrientationDetection()),
SNAPSHOT_MAX_DEPTH(new SnapshotMaxDepth());

private final ISetting<?> setting;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* 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 io.appium.uiautomator2.model.settings;

import io.appium.uiautomator2.common.exceptions.InvalidArgumentException;

public class SnapshotMaxDepth extends AbstractSetting<Integer> {
public static final String SETTING_NAME = "snapshotMaxDepth";
// Set DEFAULT_VALUE as 70 to avoid StackOverflow from infinite recursion
// https://github.com/appium/appium/issues/12545
// https://github.com/appium/appium/issues/12892
private static final int DEFAULT_VALUE = 70;
private static final int MIN_DEPTH = 1;
private static final int MAX_DEPTH = 500;
private Integer value = DEFAULT_VALUE;

public SnapshotMaxDepth() {
super(Integer.class, SETTING_NAME);
}

@Override
public Integer getValue() {
return value;
}

@Override
public Integer getDefaultValue() {
return DEFAULT_VALUE;
}

@Override
protected void apply(Integer value) {
if (value == null || value < MIN_DEPTH || value > MAX_DEPTH) {
throw new InvalidArgumentException(String.format(
"Invalid %s value specified, must be in range %s..%s. %s was given",
SETTING_NAME,
MIN_DEPTH,
MAX_DEPTH,
value
));
}
this.value = value;
}
}

0 comments on commit 9a40742

Please sign in to comment.