diff --git a/src/main/java/io/percy/appium/lib/Utils.java b/src/main/java/io/percy/appium/lib/Utils.java new file mode 100644 index 0000000..dbf1ae0 --- /dev/null +++ b/src/main/java/io/percy/appium/lib/Utils.java @@ -0,0 +1,38 @@ +package io.percy.appium.lib; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import io.percy.appium.AppPercy; + +public class Utils { + public static Integer extractStatusBarHeight(String input) { + try { + Pattern pattern = Pattern.compile("ITYPE_STATUS_BAR frame=\\[\\d+,\\d+\\]\\[\\d+,([\\d]+)\\]"); + Matcher matcher = pattern.matcher(input); + if (matcher.find()) { + return Integer.parseInt(matcher.group(1)); + } + return null; // Return null if no match found + } catch (Exception ex) { + AppPercy.log(ex.toString(), "debug"); + return null; // Return null if any error + } + } + + public static Integer extractNavigationBarHeight(String input) { + try { + Pattern pattern = Pattern.compile("ITYPE_NAVIGATION_BAR frame=\\[\\d+,([\\d]+)\\]\\[\\d+,([\\d]+)\\]"); + Matcher matcher = pattern.matcher(input); + + if (matcher.find()) { + int bottomCoordinate = Integer.parseInt(matcher.group(1)); + int topCoordinate = Integer.parseInt(matcher.group(2)); + return topCoordinate - bottomCoordinate; + } + return null; // Return null if no match found + } catch (Exception ex) { + AppPercy.log(ex.toString(), "debug"); + return null; // Return null if any error + } + } +} diff --git a/src/main/java/io/percy/appium/metadata/AndroidMetadata.java b/src/main/java/io/percy/appium/metadata/AndroidMetadata.java index 1dc41bf..b81189d 100644 --- a/src/main/java/io/percy/appium/metadata/AndroidMetadata.java +++ b/src/main/java/io/percy/appium/metadata/AndroidMetadata.java @@ -2,18 +2,23 @@ import java.util.Map; +import org.json.JSONObject; + import io.appium.java_client.AppiumDriver; import io.appium.java_client.android.AndroidDriver; import io.percy.appium.lib.Cache; +import io.percy.appium.lib.Utils; public class AndroidMetadata extends Metadata { private AndroidDriver driver; private String sessionId; + private String orientation; public AndroidMetadata(AppiumDriver driver, String deviceName, Integer statusBar, Integer navBar, String orientation, String platformVersion) { super(driver, deviceName, statusBar, navBar, orientation, platformVersion); this.driver = (AndroidDriver) driver; + this.orientation = orientation; this.sessionId = driver.getSessionId().toString(); } @@ -41,7 +46,11 @@ public Integer deviceScreenHeight() { } public Integer statBarHeight() { + Integer statBar = getStatusBar(); + if (statBar == null && orientation != null && orientation.toLowerCase().equals("auto")) { + statBar = Utils.extractStatusBarHeight(getDisplaySysDump()); + } if (statBar != null) { return statBar; } @@ -50,6 +59,9 @@ public Integer statBarHeight() { public Integer navBarHeight() { Integer navBar = getNavBar(); + if (navBar == null && orientation != null && orientation.toLowerCase().equals("auto")) { + navBar = Utils.extractNavigationBarHeight(getDisplaySysDump()); + } if (navBar != null) { return navBar; } @@ -69,4 +81,19 @@ public Integer scaleFactor() { return 1; } + public String getDisplaySysDump() { + if (Cache.CACHE_MAP.get("getDisplaySysDump_" + sessionId) == null) { + + JSONObject arguments = new JSONObject(); + arguments.put("action", "adbShell"); + JSONObject command = new JSONObject(); + command.put("command", "dumpsys window displays"); + arguments.put("arguments", command); + String resultString = driver + .executeScript(String.format("browserstack_executor: %s", arguments.toString())).toString(); + Cache.CACHE_MAP.put("getDisplaySysDump_" + sessionId, resultString); + } + return (String) Cache.CACHE_MAP.get("getDisplaySysDump_" + sessionId); + } + } diff --git a/src/main/java/io/percy/appium/providers/GenericProvider.java b/src/main/java/io/percy/appium/providers/GenericProvider.java index 39d9ad4..d53d692 100644 --- a/src/main/java/io/percy/appium/providers/GenericProvider.java +++ b/src/main/java/io/percy/appium/providers/GenericProvider.java @@ -115,29 +115,28 @@ public JSONObject screenshot(String name, ScreenshotOptions options, String platformVersion, String deviceName) throws Exception { this.metadata = MetadataHelper.resolve(driver, deviceName, options.getStatusBarHeight(), options.getNavBarHeight(), options.getOrientation(), platformVersion); - JSONObject tag = getTag(); List tiles = captureTiles(options); + // Get Tag After captureTile. This is done if orientation is auto. + // Orientation get overwrited in metadata.orientation() function. + JSONObject tag = getTag(); JSONArray ignoreRegions = findRegions( - options.getIgnoreRegionXpaths(), - options.getIgnoreRegionAccessibilityIds(), - options.getIgnoreRegionAppiumElements(), - options.getCustomIgnoreRegions() - ); + options.getIgnoreRegionXpaths(), + options.getIgnoreRegionAccessibilityIds(), + options.getIgnoreRegionAppiumElements(), + options.getCustomIgnoreRegions()); JSONArray considerRegions = findRegions( - options.getConsiderRegionXpaths(), - options.getConsiderRegionAccessibilityIds(), - options.getConsiderRegionAppiumElements(), - options.getCustomConsiderRegions() - ); + options.getConsiderRegionXpaths(), + options.getConsiderRegionAccessibilityIds(), + options.getConsiderRegionAppiumElements(), + options.getCustomConsiderRegions()); return cliWrapper.postScreenshot( - name, - tag, - tiles, - debugUrl, - getObjectForArray("ignoreElementsData", ignoreRegions), - getObjectForArray("considerElementsData", considerRegions), - options.getSync() - ); + name, + tag, + tiles, + debugUrl, + getObjectForArray("ignoreElementsData", ignoreRegions), + getObjectForArray("considerElementsData", considerRegions), + options.getSync()); } public void setMetadata(Metadata metadata) { @@ -153,11 +152,10 @@ public void setDebugUrl(String debugUrl) { } public JSONArray findRegions( - List xpaths, - List accessibilityIds, - List elements, - List locations - ) { + List xpaths, + List accessibilityIds, + List elements, + List locations) { JSONArray elementsArray = new JSONArray(); getRegionsByXpath(elementsArray, xpaths); getRegionsByIds(elementsArray, accessibilityIds); diff --git a/src/test/java/io/percy/appium/lib/UtilsTest.java b/src/test/java/io/percy/appium/lib/UtilsTest.java new file mode 100644 index 0000000..af1a66b --- /dev/null +++ b/src/test/java/io/percy/appium/lib/UtilsTest.java @@ -0,0 +1,49 @@ +package io.percy.appium.lib; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class UtilsTest { + @Test + public void testExtractStatusBarHeighWhenPatternIsPresent() { + String input = "InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][2400,74] visible=true\n" + + "InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,2358][1080,2400] visible=true"; + + int expectedStatBarHeight = 74; + int actualStatBarHeight = Utils.extractStatusBarHeight(input); + + assertEquals(expectedStatBarHeight, actualStatBarHeight); + } + + @Test + public void testExtractNavigationBarHeightWhenPatternIsPresent() { + String input = "InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][2400,74] visible=true\n" + + "InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,2358][1080,2400] visible=true"; + + int expectedNavBarHeight = 42; + int actualNavBarHeight = Utils.extractNavigationBarHeight(input); + + assertEquals(expectedNavBarHeight, actualNavBarHeight); + } + + @Test + public void testExtractStatusBarHeighWhenPatternIsNotPresent() { + String input = "RANDOM frame=[0,0][2400,74] visible=true\n" + + "RANDOM frame=[0,2358][1080,2400] visible=true"; + + Integer actualStatBarHeight = Utils.extractStatusBarHeight(input); + + assertEquals(null, actualStatBarHeight); + } + + @Test + public void testExtractNavigationBarHeightWhenPatternIsNotPresent() { + String input = "RANDOM [0,0][2400,74] visible=true\n" + + "RANDOM [0,2358][1080,2400] visible=true"; + + Integer actualNavBarHeight = Utils.extractNavigationBarHeight(input); + + assertEquals(null, actualNavBarHeight); + } +} diff --git a/src/test/java/io/percy/appium/metadata/AndroidMetadataTest.java b/src/test/java/io/percy/appium/metadata/AndroidMetadataTest.java index 6c62b9f..7f686d9 100644 --- a/src/test/java/io/percy/appium/metadata/AndroidMetadataTest.java +++ b/src/test/java/io/percy/appium/metadata/AndroidMetadataTest.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.Map; +import org.json.JSONObject; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -73,19 +74,71 @@ public void testStatBarHeight() { Assert.assertEquals(metadata.statBarHeight().intValue(), top.intValue()); } + @Test + public void testStatBarHeightWhenValueGiven() { + metadata = new AndroidMetadata(androidDriver, "Samsung Galaxy s22", 100, 200, "auto", null); + Assert.assertEquals(metadata.statBarHeight().intValue(), 100); + } + + @Test + public void testStatBarHeightForAuto() { + metadata = new AndroidMetadata(androidDriver, "Samsung Galaxy s22", null, null, "auto", null); + JSONObject arguments = new JSONObject(); + arguments.put("action", "adbShell"); + JSONObject command = new JSONObject(); + command.put("command", "dumpsys window displays"); + arguments.put("arguments", command); + + String response = "InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][2400,74] visible=true\n" + + "InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,2358][1080,2400] visible=true"; + + when(androidDriver.executeScript(String.format("browserstack_executor: %s", arguments.toString()))) + .thenReturn(response); + + Integer expectedStatBarHeight = 74; + Integer actualStatBarHeight = metadata.statBarHeight(); + Assert.assertEquals(expectedStatBarHeight, actualStatBarHeight); + } + @Test public void testNavBarHeight() { Assert.assertEquals(metadata.navBarHeight().intValue(), 2160 - (height + top)); } @Test - public void testDeviceName(){ + public void testNavBarHeightWhenValueGiven() { + metadata = new AndroidMetadata(androidDriver, "Samsung Galaxy s22", 100, 200, "auto", null); + Assert.assertEquals(metadata.navBarHeight().intValue(), 200); + } + + @Test + public void testNavBarHeightForAuto() { + metadata = new AndroidMetadata(androidDriver, "Samsung Galaxy s22", null, null, "auto", null); + JSONObject arguments = new JSONObject(); + arguments.put("action", "adbShell"); + JSONObject command = new JSONObject(); + command.put("command", "dumpsys window displays"); + arguments.put("arguments", command); + + String response = "InsetsSource type=ITYPE_STATUS_BAR frame=[0,0][2400,74] visible=true\n" + + "InsetsSource type=ITYPE_NAVIGATION_BAR frame=[0,2358][1080,2400] visible=true"; + + when(androidDriver.executeScript(String.format("browserstack_executor: %s", arguments.toString()))) + .thenReturn(response); + + Integer expectedStatBarHeight = 42; + Integer actualStatBarHeight = metadata.navBarHeight(); + Assert.assertEquals(expectedStatBarHeight, actualStatBarHeight); + } + + @Test + public void testDeviceName() { when(capabilities.getCapability("device")).thenReturn("Samsung Galaxy s22"); Assert.assertEquals(metadata.deviceName(), "Samsung Galaxy s22"); } @Test - public void testDeviceNameFromDesired(){ + public void testDeviceNameFromDesired() { Map desired = new HashMap<>(); desired.put("deviceName", "Samsung Galaxy s22"); when(capabilities.getCapability("desired")).thenReturn(desired); @@ -93,13 +146,13 @@ public void testDeviceNameFromDesired(){ } @Test - public void testOsName(){ + public void testOsName() { when(capabilities.getCapability("platformName")).thenReturn("Android"); Assert.assertEquals(metadata.osName(), "Android"); } @Test - public void testPlatformVersion(){ + public void testPlatformVersion() { when(capabilities.getCapability("platformVersion")).thenReturn("12"); Assert.assertEquals(metadata.platformVersion(), "12"); } @@ -142,7 +195,7 @@ public void testScaleFactor() { } @Test - public void testOrientatioWithNullParamAndCaps(){ + public void testOrientatioWithNullParamAndCaps() { when(androidDriver.getCapabilities().getCapability("orientation")).thenReturn(ScreenOrientation.LANDSCAPE); Assert.assertEquals(metadata.orientation(), "landscape"); }