1 /*
2  * Copyright (C) 2022 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 package com.android.launcher3.tapl;
17 
18 import static android.view.KeyEvent.KEYCODE_META_RIGHT;
19 
20 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
21 
22 import android.graphics.Point;
23 import android.graphics.Rect;
24 import android.os.SystemClock;
25 import android.text.TextUtils;
26 import android.view.MotionEvent;
27 import android.widget.TextView;
28 
29 import androidx.annotation.NonNull;
30 import androidx.test.uiautomator.By;
31 import androidx.test.uiautomator.BySelector;
32 import androidx.test.uiautomator.UiObject2;
33 
34 import org.junit.Assert;
35 
36 import java.util.List;
37 import java.util.stream.Collectors;
38 
39 /**
40  * Operations on the Taskbar from LaunchedApp.
41  */
42 public final class Taskbar {
43 
44     private final LauncherInstrumentation mLauncher;
45 
Taskbar(LauncherInstrumentation launcher)46     Taskbar(LauncherInstrumentation launcher) {
47         mLauncher = launcher;
48         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
49                 "expect new taskbar to be visible")) {
50             mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
51         }
52 
53         if (!mLauncher.isTransientTaskbar()) {
54             Assert.assertEquals("Persistent taskbar should fill screen width",
55                     getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
56         }
57     }
58 
59     /**
60      * Returns an app icon with the given name. This fails if the icon is not found.
61      */
62     @NonNull
getAppIcon(String appName)63     public TaskbarAppIcon getAppIcon(String appName) {
64         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
65                 "want to get a taskbar icon")) {
66             return new TaskbarAppIcon(mLauncher, mLauncher.waitForObjectInContainer(
67                     mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
68                     AppIcon.getAppIconSelector(appName, mLauncher)));
69         }
70     }
71 
72     /**
73      * Stashes this taskbar.
74      * <p>
75      * The taskbar must already be unstashed and in transient mode when calling this method.
76      */
swipeDownToStash()77     public void swipeDownToStash() {
78         mLauncher.assertTrue("Taskbar is not transient, swipe down not supported",
79                 mLauncher.isTransientTaskbar());
80 
81         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
82                 "want to hide the taskbar");
83              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
84             mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
85 
86             Rect taskbarBounds = getVisibleBounds();
87             int startX = taskbarBounds.centerX();
88             int startY = taskbarBounds.centerY();
89             int endX = startX;
90             int endY = mLauncher.getRealDisplaySize().y - 1;
91 
92             mLauncher.linearGesture(startX, startY, endX, endY, 10, false,
93                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
94             LauncherInstrumentation.log("swipeDownToStash: sent linear swipe down gesture");
95             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
96                     "expect transient taskbar to be hidden after swipe down")) {
97                 mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
98             }
99         }
100     }
101 
102     /**
103      * Opens the Taskbar all apps page.
104      */
openAllApps()105     public TaskbarAllApps openAllApps() {
106         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
107                 "want to open taskbar all apps");
108              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
109 
110             mLauncher.clickLauncherObject(mLauncher.waitForObjectInContainer(
111                     mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
112                     getAllAppsButtonSelector()));
113 
114             return getAllApps();
115         }
116     }
117 
118     /** Opens the Taskbar all apps page with the meta keyboard shortcut. */
openAllAppsFromKeyboardShortcut()119     public TaskbarAllApps openAllAppsFromKeyboardShortcut() {
120         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
121             mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
122             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
123                     "pressed meta key")) {
124                 return getAllApps();
125             }
126         }
127     }
128 
129     /** Returns {@link TaskbarAllApps} if it is open, otherwise fails. */
getAllApps()130     public TaskbarAllApps getAllApps() {
131         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
132                 "want to get taskbar all apps object")) {
133             return new TaskbarAllApps(mLauncher);
134         }
135     }
136 
137     /** Returns a list of app icon names on the Taskbar */
getIconNames()138     public List<String> getIconNames() {
139         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
140                 "want to get all taskbar icons")) {
141             return mLauncher.waitForObjectsInContainer(
142                     mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID),
143                     AppIcon.getAnyAppIconSelector())
144                     .stream()
145                     .map(UiObject2::getText)
146                     .filter(text -> !TextUtils.isEmpty(text)) // Filter out the all apps button
147                     .collect(Collectors.toList());
148         }
149     }
150 
getAllAppsButtonSelector()151     private static BySelector getAllAppsButtonSelector() {
152         // Look for an icon with no text
153         return By.clazz(TextView.class).text("");
154     }
155 
getVisibleBounds()156     public Rect getVisibleBounds() {
157         return mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID).getVisibleBounds();
158     }
159 
160     /**
161      * Touch either on the right or the left corner of the screen, 1 pixel from the bottom and
162      * from the sides.
163      */
touchBottomCorner(boolean tapRight)164     void touchBottomCorner(boolean tapRight) {
165         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
166                 "want to tap bottom corner on the " + (tapRight ? "right" : "left"))) {
167             final long downTime = SystemClock.uptimeMillis();
168             final Point tapTarget = new Point(
169                     tapRight
170                             ?
171                             getVisibleBounds().right
172                                     - mLauncher.getTargetInsets().right
173                                     - 1
174                             : getVisibleBounds().left
175                                     + 1,
176                     mLauncher.getRealDisplaySize().y - 1);
177 
178             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, tapTarget,
179                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
180             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, tapTarget,
181                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
182         }
183     }
184 }
185