From 373de559c2bbdcfb540ca668ba6a60122dc210db Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 19 Dec 2023 23:52:28 +0000 Subject: [PATCH] Update Launcher3 TAPL "find app icon" logic to allow whitespace. Previously this used the content description which was generally the same as the displayed text with whitespace adjustments + additional text (e.g. "Play Store has 7 notifications"). That worked fine, but I thought it would be a bit more robust to work with the text directly. Specifically, we consider it a match if all of the non-whitespace characters are there, along with optional added whitespace between characters. See TaplUtilityTests for examples. More importantly for the other change in this topic, this Pattern is also used for search result icons, to allow those tests to pass with multiline labels enabled. Bug: 315053839 Flag: LEGACY ENABLE_TWOLINE_DEVICESEARCH ENABLED Test: Manual and TaplTestsTaskbarSearch + other unit tests Change-Id: I4ad52840d743f06576d415f4e5ea6d8870e5dd2c --- .../launcher3/tapl/TaplUtilityTest.java | 41 +++++++++++++++---- .../com/android/launcher3/tapl/AppIcon.java | 33 +++++++++++---- .../launcher3/tapl/SearchResultFromQsb.java | 2 +- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java index 4a1888ae11..b6ded9751d 100644 --- a/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java +++ b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java @@ -23,16 +23,43 @@ import org.junit.Test; public class TaplUtilityTest { @Test - public void testNewStringWithRegex() { + public void testMakeMultilinePattern() { + // Original title will match. assertTrue(AppIcon.makeMultilinePattern("Play Store") - .matcher("Play Store has 7 notifications").matches()); + .matcher("Play Store").matches()); + assertTrue(AppIcon.makeMultilinePattern("PlayStore") + .matcher("PlayStore").matches()); + + // Original title with whitespace added will match. + assertTrue(AppIcon.makeMultilinePattern("PlayStore") + .matcher("Play\nStore").matches()); + assertTrue(AppIcon.makeMultilinePattern("PlayStore") + .matcher("Play Store").matches()); + // Original title with whitespace removed will also match. assertTrue(AppIcon.makeMultilinePattern("Play Store") - .matcher("Play Store!").matches()); - assertFalse(AppIcon.makeMultilinePattern("Play Store") - .matcher("play store").matches()); - assertFalse(AppIcon.makeMultilinePattern("Play Store") - .matcher("").matches()); + .matcher("PlayStore").matches()); + // Or whitespace replaced with a different kind of whitespace (both of above conditions). + assertTrue(AppIcon.makeMultilinePattern("Play Store") + .matcher("Play\nStore").matches()); assertTrue(AppIcon.makeMultilinePattern("Play Store") .matcher("Play \n Store").matches()); + + // Any non-whitespace character added to the title will not match. + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("Play Store has 7 notifications").matches()); + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("Play Store!").matches()); + // Title is case-sensitive. + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("play store").matches()); + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("play store").matches()); + // Removing non whitespace characters will not match. + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("").matches()); + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("Play Stor").matches()); + assertFalse(AppIcon.makeMultilinePattern("Play Store") + .matcher("Play").matches()); } } diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java index 85098c899c..867a1a8c05 100644 --- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java +++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java @@ -36,9 +36,23 @@ public abstract class AppIcon extends Launchable { super(launcher, icon); } + /** + * Find an app icon with the given name. + * + * @param appName app icon to look for + */ + static BySelector getAppIconSelector(String appName) { + return By.clazz(TextView.class).text(makeMultilinePattern(appName)); + } + + /** + * Find an app icon with the given name. + * + * @param appName app icon to look for + * @param launcher (optional) - only match ui elements from Launcher's package + */ static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) { - return By.clazz(TextView.class).desc(makeMultilinePattern(appName)) - .pkg(launcher.getLauncherPackageName()); + return getAppIconSelector(appName).pkg(launcher.getLauncherPackageName()); } static BySelector getMenuItemSelector(String text, LauncherInstrumentation launcher) { @@ -109,13 +123,16 @@ public abstract class AppIcon extends Launchable { } /** - * Create a regular expression pattern that matches strings starting with the app name, where - * spaces in the app name are replaced with zero or more occurrences of the "\s" character - * (which represents a whitespace character in regular expressions), followed by any characters - * after the app name. + * Create a regular expression pattern that matches strings containing all of the non-whitespace + * characters of the app name, with any amount of whitespace added between characters (e.g. + * newline for multiline app labels). */ static Pattern makeMultilinePattern(String appName) { - return Pattern.compile(appName.replaceAll("\\s+", "\\\\s*") + ".*", - Pattern.DOTALL); + // Remove any existing whitespace. + appName = appName.replaceAll("\\s", ""); + // Allow whitespace between characters, e.g. newline for 2 line app label. + StringBuilder regexBuldier = new StringBuilder("\\s*"); + appName.chars().forEach(letter -> regexBuldier.append((char) letter).append("\\s*")); + return Pattern.compile(regexBuldier.toString()); } } diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java index f0a8aa26c0..963bf79064 100644 --- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java +++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java @@ -39,7 +39,7 @@ public class SearchResultFromQsb implements SearchInputSource { /** Find the app from search results with app name. */ public AppIcon findAppIcon(String appName) { - UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName)); + UiObject2 icon = mLauncher.waitForLauncherObject(AppIcon.getAppIconSelector(appName)); return createAppIcon(icon); }