1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.tapl;
18 
19 import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
20 
21 import android.util.Log;
22 import android.widget.TextView;
23 
24 import androidx.annotation.NonNull;
25 import androidx.test.uiautomator.By;
26 import androidx.test.uiautomator.BySelector;
27 import androidx.test.uiautomator.UiObject2;
28 
29 import com.android.launcher3.testing.shared.TestProtocol;
30 
31 import java.util.regex.Pattern;
32 
33 /**
34  * App icon, whether in all apps, workspace or the taskbar.
35  */
36 public abstract class AppIcon extends Launchable {
37 
AppIcon(LauncherInstrumentation launcher, UiObject2 icon)38     AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
39         super(launcher, icon);
40     }
41 
42     /**
43      * Find an app icon with the given name.
44      *
45      * @param appName app icon to look for
46      */
getAppIconSelector(String appName)47     static BySelector getAppIconSelector(String appName) {
48         // focusable=true to avoid matching folder labels
49         return By.clazz(TextView.class).text(makeMultilinePattern(appName)).focusable(true);
50     }
51 
52     /**
53      * Find an app icon with the given name.
54      *
55      * @param appName  app icon to look for
56      * @param launcher (optional) - only match ui elements from Launcher's package
57      */
getAppIconSelector(String appName, LauncherInstrumentation launcher)58     static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) {
59         return getAppIconSelector(appName).pkg(launcher.getLauncherPackageName());
60     }
61 
getMenuItemSelector(String text, LauncherInstrumentation launcher)62     static BySelector getMenuItemSelector(String text, LauncherInstrumentation launcher) {
63         return By.clazz(TextView.class).text(text).pkg(launcher.getLauncherPackageName());
64     }
65 
getAnyAppIconSelector()66     static BySelector getAnyAppIconSelector() {
67         return By.clazz(TextView.class);
68     }
69 
getLongClickEvent()70     protected abstract Pattern getLongClickEvent();
71 
72     /**
73      * Long-clicks the icon to open its menu.
74      */
openMenu()75     public AppIconMenu openMenu() {
76         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
77             return createMenu(mLauncher.clickAndGet(
78                     mObject, /* resName= */ "popup_container", getLongClickEvent()));
79         }
80     }
81 
82     /**
83      * Long-clicks the icon to open its menu, and looks at the deep shortcuts container only.
84      */
openDeepShortcutMenu()85     public AppIconMenu openDeepShortcutMenu() {
86         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
87             return createMenu(mLauncher.clickAndGet(
88                     mObject, /* resName= */ "deep_shortcuts_container", getLongClickEvent()));
89         }
90     }
91 
createMenu(UiObject2 menu)92     protected abstract AppIconMenu createMenu(UiObject2 menu);
93 
94     @Override
addExpectedEventsForLongClick()95     protected void addExpectedEventsForLongClick() {
96         mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, getLongClickEvent());
97     }
98 
99     @Override
waitForLongPressConfirmation()100     protected void waitForLongPressConfirmation() {
101         Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
102                 "AppIcon.waitForLongPressConfirmation, resName: popupContainer");
103         mLauncher.waitForLauncherObject("popup_container");
104     }
105 
106     @Override
expectActivityStartEvents()107     protected void expectActivityStartEvents() {
108         mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
109     }
110 
111     @Override
launchableType()112     protected String launchableType() {
113         return "app icon";
114     }
115 
116     /** Return the app name of a icon */
117     @NonNull
getIconName()118     public String getIconName() {
119         return getObject().getText();
120     }
121 
122     /**
123      * Return the app name of a icon by the content description. This should be used when trying to
124      * get the name of an app where the text of it is multiline.
125      */
126     @NonNull
getAppName()127     String getAppName() {
128         return getObject().getContentDescription();
129     }
130 
131     /**
132      * Create a regular expression pattern that matches strings containing all of the non-whitespace
133      * characters of the app name, with any amount of whitespace added between characters (e.g.
134      * newline for multiline app labels).
135      */
makeMultilinePattern(String appName)136     static Pattern makeMultilinePattern(String appName) {
137         // Remove any existing whitespace.
138         appName = appName.replaceAll("\\s", "");
139         // Allow whitespace between characters, e.g. newline for 2 line app label.
140         StringBuilder regexBuldier = new StringBuilder("\\s*");
141         appName.chars().forEach(letter -> regexBuldier.append((char) letter).append("\\s*"));
142         return Pattern.compile(regexBuldier.toString());
143     }
144 }
145